From aa2458d56404a4d215a256c2581a79db5c992335 Mon Sep 17 00:00:00 2001 From: SabreCat Date: Thu, 12 May 2022 13:55:59 -0500 Subject: [PATCH 1/8] 4.230.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 60f888006e..42ed898b7d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "habitica", - "version": "4.230.0", + "version": "4.230.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 975d6cec9b..b9a6a52518 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.1", "main": "./website/server/index.js", "dependencies": { "@babel/core": "^7.17.10", From a0de2dab4938a315c694c236a0d784ec2b1b489f Mon Sep 17 00:00:00 2001 From: Sabe Jones Date: Thu, 12 May 2022 14:56:05 -0500 Subject: [PATCH 2/8] fix(tasks): don't send delta around as an array (#13967) Co-authored-by: SabreCat --- website/common/script/ops/scoreTask.js | 2 +- website/server/libs/tasks/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/website/common/script/ops/scoreTask.js b/website/common/script/ops/scoreTask.js index 5a46d01ada..335b3a85bf 100644 --- a/website/common/script/ops/scoreTask.js +++ b/website/common/script/ops/scoreTask.js @@ -362,5 +362,5 @@ export default function scoreTask (options = {}, req = {}, analytics) { checkOnboardingStatus(user, req, analytics); } - return [delta]; + return delta; } diff --git a/website/server/libs/tasks/index.js b/website/server/libs/tasks/index.js index 2e33d1da9a..48a97ffa15 100644 --- a/website/server/libs/tasks/index.js +++ b/website/server/libs/tasks/index.js @@ -404,7 +404,7 @@ async function scoreTask (user, task, direction, req, res) { const wasCompleted = task.completed; const firstTask = !user.achievements.completedTask; - const [delta] = shared.ops.scoreTask({ task, user, direction }, req, res.analytics); + const delta = shared.ops.scoreTask({ task, user, direction }, req, res.analytics); // Drop system (don't run on the client, // as it would only be discarded since ops are sent to the API, not the results) if (direction === 'up' && !firstTask) shared.fns.randomDrop(user, { task, delta }, req, res.analytics); From 761d70ec55ee18150dd85076930016958ff13569 Mon Sep 17 00:00:00 2001 From: Natalie L <78037386+CuriousMagpie@users.noreply.github.com> Date: Thu, 12 May 2022 16:14:56 -0400 Subject: [PATCH 3/8] Gifting Modal Redesign (#13964) * update selectUserModal.vue * more updates to selectUserModal.vue, typo fix in subscriber.json * remove exact sizing for selectUserModal.vue * update to size for selectUserModal.vue * added sendGiftModal.vue file * updates to selectUser & sendGift modals * making the modals go & position cursor * working working working * added a return to method * avatar display & placeholder profile.name and username * subscription-options added * added menu row & started on gem options * Added selectPage function, have not tested. * updated habitica-images * state changes * bringing in gem counter * arranging elements * state changes, gem input boxes * styling sendGiftModal.vue * more sendGiftModal.vue styling and new close.svg icon * more styling! * and more styling of send own gems part of page * images update * more styling of own gems & some attempts to adjust :class on the menu * styling styling styling * replace +/- svg, styling * styling, mostly * new SVGs * stylin' * reverting svg changes * no more stylin' * finally got the +/- icons to show up...but they're the wrong color * solved svg icon color problem! :) * habitica-images * working on sendGift part of button * trying to make it do math, failing * more attempts at math * +/- buttons work on gem pages & cost calculation on buyGems * trying to get hover colors working on +/- svgs * formatted dollar amount as currency * css/html for subscription-options & payments-buttons simplified * swag at payments-buttons parameter (not tested) * send gems from own balance works! * working on starting page * increment gem amount limited to maxGems and not < 0 * uncommented onHide() * got bg color on sub options to work! yay! * payment buttons! * making g1g1 look good * position modal on page properly & code clean-up * Changes as requested! * small color update * fixed ternary function * chore(html): indentation and comments * fix(fn): correct catch for under-0 * chore(json): whitespace Co-authored-by: SabreCat --- website/client/src/assets/svg/big-gift.svg | 27 + website/client/src/assets/svg/close.svg | 14 +- website/client/src/components/header/menu.vue | 6 +- .../src/components/payments/buttons/list.vue | 8 + .../components/payments/selectUserModal.vue | 132 +++- .../src/components/payments/sendGiftModal.vue | 634 ++++++++++++++++++ .../src/components/settings/subscription.vue | 4 - .../src/components/userMenu/profile.vue | 3 +- website/client/src/store/index.js | 3 + website/common/locales/en/groups.json | 1 + website/common/locales/en/subscriber.json | 7 +- 11 files changed, 808 insertions(+), 31 deletions(-) create mode 100644 website/client/src/assets/svg/big-gift.svg create mode 100644 website/client/src/components/payments/sendGiftModal.vue 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/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 @@ - +
+

{{ $t('choosePaymentMethod') }}

@@ -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/common/script/content/achievements.js b/website/common/script/content/achievements.js index b8f7ba8aab..f4746f86b1 100644 --- a/website/common/script/content/achievements.js +++ b/website/common/script/content/achievements.js @@ -55,27 +55,30 @@ const seasonalSpellAchievs = { }; Object.assign(achievementsData, seasonalSpellAchievs); -const masterAchievs = { +const stableAchievs = { beastMaster: { icon: 'achievement-rat', titleKey: 'beastMasterName', textKey: 'beastMasterText', text2Key: 'beastMasterText2', + notificationText: 'beastAchievement', }, mountMaster: { icon: 'achievement-wolf', titleKey: 'mountMasterName', textKey: 'mountMasterText', text2Key: 'mountMasterText2', + notificationText: 'mountAchievement', }, triadBingo: { icon: 'achievement-triadbingo', titleKey: 'triadBingoName', textKey: 'triadBingoText', text2Key: 'triadBingoText2', + notificationText: 'triadBingoAchievement', }, }; -Object.assign(achievementsData, masterAchievs); +Object.assign(achievementsData, stableAchievs); const basicAchievs = { partyUp: { @@ -122,146 +125,173 @@ const basicAchievs = { titleKey: 'invitedFriend', textKey: 'invitedFriendText', }, +}; +Object.assign(achievementsData, basicAchievs); + +const questSeriesAchievs = { lostMasterclasser: { icon: 'achievement-lostMasterclasser', titleKey: 'achievementLostMasterclasser', textKey: 'achievementLostMasterclasserText', }, - mindOverMatter: { - icon: 'achievement-mindOverMatter', - titleKey: 'achievementMindOverMatter', - textKey: 'achievementMindOverMatterText', - }, - justAddWater: { - icon: 'achievement-justAddWater', - titleKey: 'achievementJustAddWater', - textKey: 'achievementJustAddWaterText', - }, - backToBasics: { - icon: 'achievement-backToBasics', - titleKey: 'achievementBackToBasics', - textKey: 'achievementBackToBasicsText', - }, - allYourBase: { - icon: 'achievement-allYourBase', - titleKey: 'achievementAllYourBase', - textKey: 'achievementAllYourBaseText', - }, - dustDevil: { - icon: 'achievement-dustDevil', - titleKey: 'achievementDustDevil', - textKey: 'achievementDustDevilText', - }, - aridAuthority: { - icon: 'achievement-aridAuthority', - titleKey: 'achievementAridAuthority', - textKey: 'achievementAridAuthorityText', - }, - monsterMagus: { - icon: 'achievement-monsterMagus', - titleKey: 'achievementMonsterMagus', - textKey: 'achievementMonsterMagusText', - }, - undeadUndertaker: { - icon: 'achievement-undeadUndertaker', - titleKey: 'achievementUndeadUndertaker', - textKey: 'achievementUndeadUndertakerText', - }, - primedForPainting: { - icon: 'achievement-primedForPainting', - titleKey: 'achievementPrimedForPainting', - textKey: 'achievementPrimedForPaintingText', - }, - pearlyPro: { - icon: 'achievement-pearlyPro', - titleKey: 'achievementPearlyPro', - textKey: 'achievementPearlyProText', - }, - tickledPink: { - icon: 'achievement-tickledPink', - titleKey: 'achievementTickledPink', - textKey: 'achievementTickledPinkText', - }, - rosyOutlook: { - icon: 'achievement-rosyOutlook', - titleKey: 'achievementRosyOutlook', - textKey: 'achievementRosyOutlookText', - }, - bugBonanza: { - icon: 'achievement-bugBonanza', - titleKey: 'achievementBugBonanza', - textKey: 'achievementBugBonanzaText', - }, bareNecessities: { icon: 'achievement-bareNecessities', titleKey: 'achievementBareNecessities', textKey: 'achievementBareNecessitiesText', }, + bugBonanza: { + icon: 'achievement-bugBonanza', + titleKey: 'achievementBugBonanza', + textKey: 'achievementBugBonanzaText', + }, freshwaterFriends: { icon: 'achievement-freshwaterFriends', titleKey: 'achievementFreshwaterFriends', textKey: 'achievementFreshwaterFriendsText', }, - goodAsGold: { - icon: 'achievement-goodAsGold', - titleKey: 'achievementGoodAsGold', - textKey: 'achievementGoodAsGoldText', + justAddWater: { + icon: 'achievement-justAddWater', + titleKey: 'achievementJustAddWater', + textKey: 'achievementJustAddWaterText', }, - allThatGlitters: { - icon: 'achievement-allThatGlitters', - titleKey: 'achievementAllThatGlitters', - textKey: 'achievementAllThatGlittersText', - }, - boneCollector: { - icon: 'achievement-boneCollector', - titleKey: 'achievementBoneCollector', - textKey: 'achievementBoneCollectorText', - }, - skeletonCrew: { - icon: 'achievement-skeletonCrew', - titleKey: 'achievementSkeletonCrew', - textKey: 'achievementSkeletonCrewText', - }, - seeingRed: { - icon: 'achievement-seeingRed', - titleKey: 'achievementSeeingRed', - textKey: 'achievementSeeingRedText', - }, - redLetterDay: { - icon: 'achievement-redLetterDay', - titleKey: 'achievementRedLetterDay', - textKey: 'achievementRedLetterDayText', - }, - legendaryBestiary: { - icon: 'achievement-legendaryBestiary', - titleKey: 'achievementLegendaryBestiary', - textKey: 'achievementLegendaryBestiaryText', + mindOverMatter: { + icon: 'achievement-mindOverMatter', + titleKey: 'achievementMindOverMatter', + textKey: 'achievementMindOverMatterText', }, seasonalSpecialist: { icon: 'achievement-seasonalSpecialist', titleKey: 'achievementSeasonalSpecialist', textKey: 'achievementSeasonalSpecialistText', }, - violetsAreBlue: { - icon: 'achievement-violetsAreBlue', - titleKey: 'achievementVioletsAreBlue', - textKey: 'achievementVioletsAreBlueText', +}; +Object.assign(achievementsData, questSeriesAchievs); + +const animalSetAchievs = { + legendaryBestiary: { + icon: 'achievement-legendaryBestiary', + titleKey: 'achievementLegendaryBestiary', + textKey: 'achievementLegendaryBestiaryText', }, - wildBlueYonder: { - icon: 'achievement-wildBlueYonder', - titleKey: 'achievementWildBlueYonder', - textKey: 'achievementWildBlueYonderText', + birdsOfAFeather: { + icon: 'achievement-birdsOfAFeather', + titleKey: 'achievementBirdsOfAFeather', + textKey: 'achievementBirdsOfAFeatherText', }, domesticated: { icon: 'achievement-domesticated', titleKey: 'achievementDomesticated', textKey: 'achievementDomesticatedText', }, + zodiacZookeeper: { + icon: 'achievement-zodiac', + titleKey: 'achievementZodiacZookeeper', + textKey: 'achievementZodiacZookeeperText', + }, +}; +Object.assign(achievementsData, animalSetAchievs); + +const petColorAchievs = { + backToBasics: { + icon: 'achievement-backToBasics', + titleKey: 'achievementBackToBasics', + textKey: 'achievementBackToBasicsText', + }, + dustDevil: { + icon: 'achievement-dustDevil', + titleKey: 'achievementDustDevil', + textKey: 'achievementDustDevilText', + }, + monsterMagus: { + icon: 'achievement-monsterMagus', + titleKey: 'achievementMonsterMagus', + textKey: 'achievementMonsterMagusText', + }, + primedForPainting: { + icon: 'achievement-primedForPainting', + titleKey: 'achievementPrimedForPainting', + textKey: 'achievementPrimedForPaintingText', + }, + tickledPink: { + icon: 'achievement-tickledPink', + titleKey: 'achievementTickledPink', + textKey: 'achievementTickledPinkText', + }, + goodAsGold: { + icon: 'achievement-goodAsGold', + titleKey: 'achievementGoodAsGold', + textKey: 'achievementGoodAsGoldText', + }, + boneCollector: { + icon: 'achievement-boneCollector', + titleKey: 'achievementBoneCollector', + textKey: 'achievementBoneCollectorText', + }, + seeingRed: { + icon: 'achievement-seeingRed', + titleKey: 'achievementSeeingRed', + textKey: 'achievementSeeingRedText', + modalTextKey: 'achievementSeeingRedModalText', + }, + violetsAreBlue: { + icon: 'achievement-violetsAreBlue', + titleKey: 'achievementVioletsAreBlue', + textKey: 'achievementVioletsAreBlueText', + }, shadyCustomer: { icon: 'achievement-shadyCustomer', titleKey: 'achievementShadyCustomer', textKey: 'achievementShadyCustomerText', }, +}; +Object.assign(achievementsData, petColorAchievs); + +const mountColorAchievs = { + allYourBase: { + icon: 'achievement-allYourBase', + titleKey: 'achievementAllYourBase', + textKey: 'achievementAllYourBaseText', + }, + aridAuthority: { + icon: 'achievement-aridAuthority', + titleKey: 'achievementAridAuthority', + textKey: 'achievementAridAuthorityText', + }, + undeadUndertaker: { + icon: 'achievement-undeadUndertaker', + titleKey: 'achievementUndeadUndertaker', + textKey: 'achievementUndeadUndertakerText', + }, + pearlyPro: { + icon: 'achievement-pearlyPro', + titleKey: 'achievementPearlyPro', + textKey: 'achievementPearlyProText', + }, + rosyOutlook: { + icon: 'achievement-rosyOutlook', + titleKey: 'achievementRosyOutlook', + textKey: 'achievementRosyOutlookText', + }, + allThatGlitters: { + icon: 'achievement-allThatGlitters', + titleKey: 'achievementAllThatGlitters', + textKey: 'achievementAllThatGlittersText', + }, + skeletonCrew: { + icon: 'achievement-skeletonCrew', + titleKey: 'achievementSkeletonCrew', + textKey: 'achievementSkeletonCrewText', + }, + redLetterDay: { + icon: 'achievement-redLetterDay', + titleKey: 'achievementRedLetterDay', + textKey: 'achievementRedLetterDayText', + }, + wildBlueYonder: { + icon: 'achievement-wildBlueYonder', + titleKey: 'achievementWildBlueYonder', + textKey: 'achievementWildBlueYonderText', + }, shadeOfItAll: { icon: 'achievement-shadeOfItAll', titleKey: 'achievementShadeOfItAll', @@ -278,7 +308,7 @@ const basicAchievs = { textKey: 'achievementBirdsOfAFeatherText', }, }; -Object.assign(achievementsData, basicAchievs); +Object.assign(achievementsData, mountColorAchievs); const onboardingAchievs = { createdTask: { diff --git a/website/common/script/content/constants/animalColorAchievements.js b/website/common/script/content/constants/animalColorAchievements.js index d16883d612..62eafd83c2 100644 --- a/website/common/script/content/constants/animalColorAchievements.js +++ b/website/common/script/content/constants/animalColorAchievements.js @@ -2,72 +2,72 @@ const ANIMAL_COLOR_ACHIEVEMENTS = [ { color: 'Base', petAchievement: 'backToBasics', - petNotificationType: 'ACHIEVEMENT_BACK_TO_BASICS', + petNotificationType: 'ACHIEVEMENT_PET_COLOR', mountAchievement: 'allYourBase', - mountNotificationType: 'ACHIEVEMENT_ALL_YOUR_BASE', + mountNotificationType: 'ACHIEVEMENT_MOUNT_COLOR', }, { color: 'Desert', petAchievement: 'dustDevil', - petNotificationType: 'ACHIEVEMENT_DUST_DEVIL', + petNotificationType: 'ACHIEVEMENT_PET_COLOR', mountAchievement: 'aridAuthority', - mountNotificationType: 'ACHIEVEMENT_ARID_AUTHORITY', + mountNotificationType: 'ACHIEVEMENT_MOUNT_COLOR', }, { color: 'Zombie', petAchievement: 'monsterMagus', - petNotificationType: 'ACHIEVEMENT_MONSTER_MAGUS', + petNotificationType: 'ACHIEVEMENT_PET_COLOR', mountAchievement: 'undeadUndertaker', - mountNotificationType: 'ACHIEVEMENT_UNDEAD_UNDERTAKER', + mountNotificationType: 'ACHIEVEMENT_MOUNT_COLOR', }, { color: 'White', petAchievement: 'primedForPainting', - petNotificationType: 'ACHIEVEMENT_PRIMED_FOR_PAINTING', + petNotificationType: 'ACHIEVEMENT_PET_COLOR', mountAchievement: 'pearlyPro', - mountNotificationType: 'ACHIEVEMENT_PEARLY_PRO', + mountNotificationType: 'ACHIEVEMENT_MOUNT_COLOR', }, { color: 'CottonCandyPink', petAchievement: 'tickledPink', - petNotificationType: 'ACHIEVEMENT_TICKLED_PINK', + petNotificationType: 'ACHIEVEMENT_PET_COLOR', mountAchievement: 'rosyOutlook', - mountNotificationType: 'ACHIEVEMENT_ROSY_OUTLOOK', + mountNotificationType: 'ACHIEVEMENT_MOUNT_COLOR', }, { color: 'Golden', petAchievement: 'goodAsGold', - petNotificationType: 'ACHIEVEMENT_GOOD_AS_GOLD', + petNotificationType: 'ACHIEVEMENT_PET_COLOR', mountAchievement: 'allThatGlitters', - mountNotificationType: 'ACHIEVEMENT_ALL_THAT_GLITTERS', + mountNotificationType: 'ACHIEVEMENT_MOUNT_COLOR', }, { color: 'Skeleton', petAchievement: 'boneCollector', - petNotificationType: 'ACHIEVEMENT_BONE_COLLECTOR', + petNotificationType: 'ACHIEVEMENT_PET_COLOR', mountAchievement: 'skeletonCrew', - mountNotificationType: 'ACHIEVEMENT_SKELETON_CREW', + mountNotificationType: 'ACHIEVEMENT_MOUNT_COLOR', }, { color: 'Red', petAchievement: 'seeingRed', - petNotificationType: 'ACHIEVEMENT_SEEING_RED', + petNotificationType: 'ACHIEVEMENT_PET_COLOR', mountAchievement: 'redLetterDay', - mountNotificationType: 'ACHIEVEMENT_RED_LETTER_DAY', + mountNotificationType: 'ACHIEVEMENT_MOUNT_COLOR', }, { color: 'CottonCandyBlue', petAchievement: 'violetsAreBlue', - petNotificationType: 'ACHIEVEMENT_VIOLETS_ARE_BLUE', + petNotificationType: 'ACHIEVEMENT_PET_COLOR', mountAchievement: 'wildBlueYonder', - mountNotificationType: 'ACHIEVEMENT_WILD_BLUE_YONDER', + mountNotificationType: 'ACHIEVEMENT_MOUNT_COLOR', }, { color: 'Shade', petAchievement: 'shadyCustomer', - petNotificationType: 'ACHIEVEMENT_SHADY_CUSTOMER', + petNotificationType: 'ACHIEVEMENT_PET_COLOR', mountAchievement: 'shadeOfItAll', - mountNotificationType: 'ACHIEVEMENT_SHADE_OF_IT_ALL', + mountNotificationType: 'ACHIEVEMENT_MOUNT_COLOR', }, ]; diff --git a/website/common/script/content/constants/animalSetAchievements.js b/website/common/script/content/constants/animalSetAchievements.js index 55e89301c4..25f9018983 100644 --- a/website/common/script/content/constants/animalSetAchievements.js +++ b/website/common/script/content/constants/animalSetAchievements.js @@ -9,7 +9,7 @@ const ANIMAL_SET_ACHIEVEMENTS = { 'Unicorn', ], achievementKey: 'legendaryBestiary', - notificationType: 'ACHIEVEMENT_LEGENDARY_BESTIARY', + notificationType: 'ACHIEVEMENT_ANIMAL_SET', }, birdsOfAFeather: { type: 'pet', @@ -24,7 +24,7 @@ const ANIMAL_SET_ACHIEVEMENTS = { 'Peacock', ], achievementKey: 'birdsOfAFeather', - notificationType: 'ACHIEVEMENT_BIRDS_OF_A_FEATHER', + notificationType: 'ACHIEVEMENT_ANIMAL_SET', }, domesticated: { type: 'pet', @@ -39,7 +39,7 @@ const ANIMAL_SET_ACHIEVEMENTS = { 'Cow', ], achievementKey: 'domesticated', - notificationType: 'ACHIEVEMENT_DOMESTICATED', + notificationType: 'ACHIEVEMENT_ANIMAL_SET', }, zodiacZookeeper: { type: 'pet', @@ -53,12 +53,12 @@ const ANIMAL_SET_ACHIEVEMENTS = { 'Monkey', 'Rooster', 'Wolf', - 'TigerCub', + 'Tiger', 'FlyingPig', 'Dragon', ], achievementKey: 'zodiacZookeeper', - notificationType: 'ACHIEVEMENT_ZODIAC_ZOOKEEPER', + notificationType: 'ACHIEVEMENT_ANIMAL_SET', }, }; diff --git a/website/common/script/content/constants/index.js b/website/common/script/content/constants/index.js index 044bb68039..b9200cac6b 100644 --- a/website/common/script/content/constants/index.js +++ b/website/common/script/content/constants/index.js @@ -32,6 +32,7 @@ export { default as SEASONAL_SETS } from './seasonalSets'; export { default as ANIMAL_COLOR_ACHIEVEMENTS } from './animalColorAchievements'; export { default as ANIMAL_SET_ACHIEVEMENTS } from './animalSetAchievements'; export { default as QUEST_SERIES_ACHIEVEMENTS } from './questSeriesAchievements'; +export { default as STABLE_ACHIEVEMENTS } from './stableAchievements'; export { default as ITEM_LIST } from './itemList'; export { default as QUEST_SERIES } from '../quests/series'; export { default as QUEST_MASTERCLASSER } from '../quests/masterclasser'; diff --git a/website/common/script/content/constants/questSeriesAchievements.js b/website/common/script/content/constants/questSeriesAchievements.js index f9ca87a489..a91334a172 100644 --- a/website/common/script/content/constants/questSeriesAchievements.js +++ b/website/common/script/content/constants/questSeriesAchievements.js @@ -17,10 +17,21 @@ const QUEST_SERIES_ACHIEVEMENTS = { 'lostMasterclasser3', 'lostMasterclasser4', ], - mindOverMatter: [ - 'rock', - 'slime', - 'yarn', + bareNecessities: [ + 'monkey', + 'sloth', + 'treeling', + ], + bugBonanza: [ + 'beetle', + 'butterfly', + 'snail', + 'spider', + ], + freshwaterFriends: [ + 'axolotl', + 'frog', + 'hippo', ], justAddWater: [ 'octopus', @@ -32,21 +43,10 @@ const QUEST_SERIES_ACHIEVEMENTS = { 'seaserpent', 'dolphin', ], - bugBonanza: [ - 'beetle', - 'butterfly', - 'snail', - 'spider', - ], - bareNecessities: [ - 'monkey', - 'sloth', - 'treeling', - ], - freshwaterFriends: [ - 'axolotl', - 'frog', - 'hippo', + mindOverMatter: [ + 'rock', + 'slime', + 'yarn', ], seasonalSpecialist: [ 'egg', diff --git a/website/common/script/content/constants/stableAchievements.js b/website/common/script/content/constants/stableAchievements.js new file mode 100644 index 0000000000..b069ea0dbd --- /dev/null +++ b/website/common/script/content/constants/stableAchievements.js @@ -0,0 +1,16 @@ +const STABLE_ACHIEVEMENTS = { + ACHIEVEMENT_BEAST_MASTER: { + masterAchievement: 'beastMasterName', + masterNotificationType: 'ACHIEVEMENT_STABLE', + }, + ACHIEVEMENT_MOUNT_MASTER: { + masterAchievement: 'mountMasterName', + masterNotificationType: 'ACHIEVEMENT_STABLE', + }, + ACHIEVEMENT_TRIAD_BINGO: { + masterAchievement: 'triadBingoName', + masterNotificationType: 'ACHIEVEMENT_STABLE', + }, +}; + +export default STABLE_ACHIEVEMENTS; diff --git a/website/common/script/content/index.js b/website/common/script/content/index.js index 9d28943e22..474a9f64db 100644 --- a/website/common/script/content/index.js +++ b/website/common/script/content/index.js @@ -12,6 +12,7 @@ import { QUEST_SERIES_ACHIEVEMENTS, ANIMAL_COLOR_ACHIEVEMENTS, ANIMAL_SET_ACHIEVEMENTS, + STABLE_ACHIEVEMENTS, } from './constants'; import achievements from './achievements'; @@ -41,6 +42,7 @@ api.achievements = achievements; api.questSeriesAchievements = QUEST_SERIES_ACHIEVEMENTS; api.animalColorAchievements = ANIMAL_COLOR_ACHIEVEMENTS; api.animalSetAchievements = ANIMAL_SET_ACHIEVEMENTS; +api.stableAchievements = STABLE_ACHIEVEMENTS; api.quests = quests; api.questsByLevel = questsByLevel; diff --git a/website/common/script/ops/feed.js b/website/common/script/ops/feed.js index 79bd7489cb..9170b728dc 100644 --- a/website/common/script/ops/feed.js +++ b/website/common/script/ops/feed.js @@ -130,6 +130,7 @@ export default function feed (user, req = {}, analytics) { if (user.addNotification) { const achievementString = `achievement${upperFirst(achievement.mountAchievement)}`; user.addNotification(achievement.mountNotificationType, { + label: `${'achievement'}: ${achievementString}`, achievement: achievement.mountAchievement, message: `${i18n.t('modalAchievement')} ${i18n.t(achievementString)}`, modalText: i18n.t(`${achievementString}ModalText`), diff --git a/website/common/script/ops/hatch.js b/website/common/script/ops/hatch.js index 542312729c..0fec8d3833 100644 --- a/website/common/script/ops/hatch.js +++ b/website/common/script/ops/hatch.js @@ -72,6 +72,7 @@ export default function hatch (user, req = {}, analytics) { if (user.addNotification) { const achievementString = `achievement${upperFirst(achievement.petAchievement)}`; user.addNotification(achievement.petNotificationType, { + label: `${'achievement'}: ${achievementString}`, achievement: achievement.petAchievement, message: `${i18n.t('modalAchievement')} ${i18n.t(achievementString)}`, modalText: i18n.t(`${achievementString}ModalText`), @@ -100,6 +101,7 @@ export default function hatch (user, req = {}, analytics) { if (user.addNotification) { const achievementString = `achievement${upperFirst(achievement.achievementKey)}`; user.addNotification(achievement.notificationType, { + label: `${'achievement'}: ${achievementString}`, achievement: achievement.achievementKey, message: `${i18n.t('modalAchievement')} ${i18n.t(achievementString)}`, modalText: i18n.t(`${achievementString}ModalText`), diff --git a/website/server/models/group.js b/website/server/models/group.js index 213ef339e9..6ccf73613f 100644 --- a/website/server/models/group.js +++ b/website/server/models/group.js @@ -999,10 +999,9 @@ schema.methods.finishQuest = async function finishQuest (quest) { const questAchievementUpdate = { $set: {}, $push: {} }; questAchievementUpdate.$set[`achievements.${achievement}`] = true; const achievementTitleCase = `${achievement.slice(0, 1).toUpperCase()}${achievement.slice(1, achievement.length)}`; - const achievementSnakeCase = `ACHIEVEMENT_${_.snakeCase(achievement).toUpperCase()}`; questAchievementUpdate.$push = { notifications: new UserNotification({ - type: achievementSnakeCase, + type: 'ACHIEVEMENT_QUESTS', data: { achievement, message: `${shared.i18n.t('modalAchievement')} ${shared.i18n.t(`achievement${achievementTitleCase}`)}`, diff --git a/website/server/models/user/hooks.js b/website/server/models/user/hooks.js index 597db34706..93a4df68b9 100644 --- a/website/server/models/user/hooks.js +++ b/website/server/models/user/hooks.js @@ -258,7 +258,13 @@ schema.pre('save', true, function preSaveUser (next, done) { && this.achievements.beastMaster !== true ) { this.achievements.beastMaster = true; - this.addNotification('ACHIEVEMENT_BEAST_MASTER'); + this.addNotification( + 'ACHIEVEMENT_STABLE', + { + achievement: 'beastMaster', + achievementNotification: 'beastAchievement', + }, + ); } // Determines if Mount Master should be awarded @@ -269,7 +275,13 @@ schema.pre('save', true, function preSaveUser (next, done) { && this.achievements.mountMaster !== true ) { this.achievements.mountMaster = true; - this.addNotification('ACHIEVEMENT_MOUNT_MASTER'); + this.addNotification( + 'ACHIEVEMENT_STABLE', + { + achievement: 'mountMaster', + achievementNotification: 'mountAchievement', + }, + ); } // Determines if Triad Bingo should be awarded @@ -281,7 +293,13 @@ schema.pre('save', true, function preSaveUser (next, done) { && this.achievements.triadBingo !== true ) { this.achievements.triadBingo = true; - this.addNotification('ACHIEVEMENT_TRIAD_BINGO'); + this.addNotification( + 'ACHIEVEMENT_STABLE', + { + achievement: 'triadBingo', + achievementNotification: 'triadBingoAchievement', + }, + ); } // EXAMPLE CODE for allowing all existing and new players to be diff --git a/website/server/models/userNotification.js b/website/server/models/userNotification.js index c6b12351e7..325fc672f5 100644 --- a/website/server/models/userNotification.js +++ b/website/server/models/userNotification.js @@ -5,75 +5,85 @@ import validator from 'validator'; import baseModel from '../libs/baseModel'; const NOTIFICATION_TYPES = [ - 'DROPS_ENABLED', // unused - 'REBIRTH_ENABLED', - 'WON_CHALLENGE', - 'STREAK_ACHIEVEMENT', - 'ULTIMATE_GEAR_ACHIEVEMENT', - 'REBIRTH_ACHIEVEMENT', - 'NEW_CONTRIBUTOR_LEVEL', + // general notifications + 'CARD_RECEIVED', 'CRON', + 'DROP_CAP_REACHED', + 'DROPS_ENABLED', // unused + 'FIRST_DROPS', + 'GIFT_ONE_GET_ONE', + 'GROUP_INVITE_ACCEPTED', 'GROUP_TASK_APPROVAL', 'GROUP_TASK_APPROVED', 'GROUP_TASK_ASSIGNED', 'GROUP_TASK_CLAIMED', 'GROUP_TASK_NEEDS_WORK', - 'LOGIN_INCENTIVE', - 'GROUP_INVITE_ACCEPTED', - 'SCORED_TASK', - 'BOSS_DAMAGE', // Not used currently but kept to avoid validation errors - 'GIFT_ONE_GET_ONE', 'GUILD_PROMPT', - 'GUILD_JOINED_ACHIEVEMENT', - 'CHALLENGE_JOINED_ACHIEVEMENT', - 'INVITED_FRIEND_ACHIEVEMENT', - 'CARD_RECEIVED', - 'NEW_MYSTERY_ITEMS', - 'UNALLOCATED_STATS_POINTS', - 'NEW_INBOX_MESSAGE', - 'NEW_STUFF', + 'LEVELED_UP', // not in use + 'LOGIN_INCENTIVE', 'NEW_CHAT_MESSAGE', - 'LEVELED_UP', // Not in use - 'FIRST_DROPS', + 'NEW_CONTRIBUTOR_LEVEL', + 'NEW_INBOX_MESSAGE', + 'NEW_MYSTERY_ITEMS', + 'NEW_STUFF', 'ONBOARDING_COMPLETE', - 'ACHIEVEMENT_ALL_YOUR_BASE', - 'ACHIEVEMENT_BACK_TO_BASICS', - 'ACHIEVEMENT_JUST_ADD_WATER', - 'ACHIEVEMENT_LOST_MASTERCLASSER', - 'ACHIEVEMENT_MIND_OVER_MATTER', - 'ACHIEVEMENT_DUST_DEVIL', - 'ACHIEVEMENT_ARID_AUTHORITY', - 'ACHIEVEMENT_PARTY_UP', - 'ACHIEVEMENT_PARTY_ON', - 'ACHIEVEMENT_BEAST_MASTER', - 'ACHIEVEMENT_MOUNT_MASTER', - 'ACHIEVEMENT_TRIAD_BINGO', - 'ACHIEVEMENT_MONSTER_MAGUS', - 'ACHIEVEMENT_UNDEAD_UNDERTAKER', - 'ACHIEVEMENT_PRIMED_FOR_PAINTING', - 'ACHIEVEMENT_PEARLY_PRO', - 'ACHIEVEMENT_TICKLED_PINK', - 'ACHIEVEMENT_ROSY_OUTLOOK', - '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', + 'REBIRTH_ENABLED', + 'SCORED_TASK', + 'UNALLOCATED_STATS_POINTS', + 'WON_CHALLENGE', + // achievement notifications 'ACHIEVEMENT', // generic achievement notification, details inside `notification.data` - 'DROP_CAP_REACHED', + 'CHALLENGE_JOINED_ACHIEVEMENT', + 'GUILD_JOINED_ACHIEVEMENT', + 'ACHIEVEMENT_PARTY_ON', + 'ACHIEVEMENT_PARTY_UP', + 'INVITED_FRIEND_ACHIEVEMENT', + 'REBIRTH_ACHIEVEMENT', + 'STREAK_ACHIEVEMENT', + 'ULTIMATE_GEAR_ACHIEVEMENT', + 'ACHIEVEMENT_STABLE', + 'ACHIEVEMENT_QUESTS', + 'ACHIEVEMENT_ANIMAL_SET', + 'ACHIEVEMENT_PET_COLOR', + 'ACHIEVEMENT_MOUNT_COLOR', + // Deprecated notification types. Can be removed once old data is cleaned out + 'BOSS_DAMAGE', // deprecated + 'ACHIEVEMENT_ALL_YOUR_BASE', // deprecated + 'ACHIEVEMENT_BACK_TO_BASICS', // deprecated + 'ACHIEVEMENT_JUST_ADD_WATER', // deprecated + 'ACHIEVEMENT_LOST_MASTERCLASSER', // deprecated + 'ACHIEVEMENT_MIND_OVER_MATTER', // deprecated + 'ACHIEVEMENT_DUST_DEVIL', // deprecated + 'ACHIEVEMENT_ARID_AUTHORITY', // deprecated + 'ACHIEVEMENT_PARTY_UP', // deprecated + 'ACHIEVEMENT_PARTY_ON', // deprecated + 'ACHIEVEMENT_BEAST_MASTER', // deprecated + 'ACHIEVEMENT_MOUNT_MASTER', // deprecated + 'ACHIEVEMENT_TRIAD_BINGO', // deprecated + 'ACHIEVEMENT_MONSTER_MAGUS', // deprecated + 'ACHIEVEMENT_UNDEAD_UNDERTAKER', // deprecated + 'ACHIEVEMENT_PRIMED_FOR_PAINTING', // deprecated + 'ACHIEVEMENT_PEARLY_PRO', // deprecated + 'ACHIEVEMENT_TICKLED_PINK', // deprecated + 'ACHIEVEMENT_ROSY_OUTLOOK', // deprecated + 'ACHIEVEMENT_BUG_BONANZA', // deprecated + 'ACHIEVEMENT_BARE_NECESSITIES', // deprecated + 'ACHIEVEMENT_FRESHWATER_FRIENDS', // deprecated + 'ACHIEVEMENT_GOOD_AS_GOLD', // deprecated + 'ACHIEVEMENT_ALL_THAT_GLITTERS', // deprecated + 'ACHIEVEMENT_BONE_COLLECTOR', // deprecated + 'ACHIEVEMENT_SKELETON_CREW', // deprecated + 'ACHIEVEMENT_SEEING_RED', // deprecated + 'ACHIEVEMENT_RED_LETTER_DAY', // deprecated + 'ACHIEVEMENT_LEGENDARY_BESTIARY', // deprecated + 'ACHIEVEMENT_SEASONAL_SPECIALIST', // deprecated + 'ACHIEVEMENT_VIOLETS_ARE_BLUE', // deprecated + 'ACHIEVEMENT_WILD_BLUE_YONDER', // deprecated + 'ACHIEVEMENT_DOMESTICATED', // deprecated + 'ACHIEVEMENT_SHADY_CUSTOMER', // deprecated + 'ACHIEVEMENT_SHADE_OF_IT_ALL', // deprecated + 'ACHIEVEMENT_ZODIAC_ZOOKEEPER', // deprecated + 'ACHIEVEMENT_BIRDS_OF_A_FEATHER', // deprecated ]; const { Schema } = mongoose; From 5bc544c481096d8ca73fca22c048edd6c627d8a0 Mon Sep 17 00:00:00 2001 From: Megan Searles <8675568+megansearles@users.noreply.github.com> Date: Fri, 13 May 2022 15:11:49 -0600 Subject: [PATCH 6/8] for locking items in market, special overrides available set. fixes #13798 (#13817) * for locking items, special overrides available * fix(market): allow purchase of broken item Co-authored-by: Megan Shepherd Co-authored-by: SabreCat --- website/common/script/libs/shops.js | 12 ++++++------ website/common/script/ops/buy/buyMarketGear.js | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/website/common/script/libs/shops.js b/website/common/script/libs/shops.js index a278069192..662f461750 100644 --- a/website/common/script/libs/shops.js +++ b/website/common/script/libs/shops.js @@ -108,12 +108,6 @@ shops.checkMarketGearLocked = function checkMarketGearLocked (user, items) { gear.locked = true; } - if (Boolean(gear.specialClass) && Boolean(gear.set)) { - const currentSet = gear.set === seasonalShopConfig.pinnedSets[gear.specialClass]; - - gear.locked = currentSet && user.stats.class !== gear.specialClass; - } - if (gear.canOwn) { gear.locked = !gear.canOwn(user); } @@ -124,6 +118,12 @@ shops.checkMarketGearLocked = function checkMarketGearLocked (user, items) { gear.locked = true; } + if (Boolean(gear.specialClass) && Boolean(gear.set)) { + const currentSet = gear.set === seasonalShopConfig.pinnedSets[gear.specialClass]; + + gear.locked = currentSet && user.stats.class !== gear.specialClass; + } + gear.owned = itemOwned; // @TODO: I'm not sure what the logic for locking is supposed to be diff --git a/website/common/script/ops/buy/buyMarketGear.js b/website/common/script/ops/buy/buyMarketGear.js index 8c87ef6fa2..83e638360d 100644 --- a/website/common/script/ops/buy/buyMarketGear.js +++ b/website/common/script/ops/buy/buyMarketGear.js @@ -28,7 +28,7 @@ export class BuyMarketGearOperation extends AbstractGoldItemOperation { // eslin const checkSpecialClass = item.klass === 'special' && item.specialClass && item.specialClass !== user.stats.class; // check for different class gear - if (checkKlass || checkSpecialClass) { + if ((checkKlass || checkSpecialClass) && user.items.gear.owned[item.key] !== false) { throw new NotAuthorized(this.i18n('cannotBuyItem')); } } From 4e78d72ceea4e60fc72a158c5501fc4893fad4c2 Mon Sep 17 00:00:00 2001 From: Natalie L <78037386+CuriousMagpie@users.noreply.github.com> Date: Tue, 17 May 2022 10:32:50 -0400 Subject: [PATCH 7/8] May 2022 Magic Hatching Potions and Quest Bundle (#13979) * May 2022 magic hatching potions and quest bundle * fix(string): typo * fix(content): add and use event Co-authored-by: SabreCat --- website/common/locales/en/questsContent.json | 2 +- website/common/script/content/bundles.js | 2 +- .../common/script/content/constants/events.js | 8 +++++++- .../common/script/content/hatching-potions.js | 11 +++++----- .../script/content/shop-featuredItems.js | 20 +++++++++---------- 5 files changed, 25 insertions(+), 18 deletions(-) diff --git a/website/common/locales/en/questsContent.json b/website/common/locales/en/questsContent.json index c969c30ef0..d0fce2dd93 100644 --- a/website/common/locales/en/questsContent.json +++ b/website/common/locales/en/questsContent.json @@ -780,7 +780,7 @@ "rockingReptilesNotes": "Contains 'The Insta-Gator,' 'The Serpent of Distraction,' and 'The Veloci-Rapper.' Available until September 30.", "delightfulDinosText": "Delightful Dinos Quest Bundle", - "delightfulDinosNotes": "Contains 'The Pterror-dactyl,' 'The Trampling Triceratops,' and 'The Dinosaur Unearthed.' Available until November 30.", + "delightfulDinosNotes": "Contains 'The Pterror-dactyl,' 'The Trampling Triceratops,' and 'The Dinosaur Unearthed.' Available until May 31.", "questAmberText": "The Amber Alliance", "questAmberNotes": "You’re sitting in the Tavern with @beffymaroo and @-Tyr- when @Vikte bursts through the door and excitedly tells you about the rumors of another type of Magic Hatching Potion hidden in the Taskwoods. Having completed your Dailies, the three of you immediately agree to help @Vikte on their search. After all, what’s the harm in a little adventure?

After walking through the Taskwoods for hours, you’re beginning to regret joining such a wild chase. You’re about to head home, when you hear a surprised yelp and turn to see a huge lizard with shiny amber scales coiled around a tree, clutching @Vikte in her claws. @beffymaroo reaches for her sword.

“Wait!” cries @-Tyr-. “It’s the Trerezin! She’s not dangerous, just dangerously clingy!”", diff --git a/website/common/script/content/bundles.js b/website/common/script/content/bundles.js index bfb7429b5a..5179cb1cd5 100644 --- a/website/common/script/content/bundles.js +++ b/website/common/script/content/bundles.js @@ -220,7 +220,7 @@ const bundles = { 'trex_undead', ], canBuy () { - return moment().isBetween('2019-11-14', '2019-12-02'); + return moment().isBetween('2022-05-16', '2022-05-31'); }, type: 'quests', value: 7, diff --git a/website/common/script/content/constants/events.js b/website/common/script/content/constants/events.js index 32fdcf3734..9ed33d8edb 100644 --- a/website/common/script/content/constants/events.js +++ b/website/common/script/content/constants/events.js @@ -10,11 +10,17 @@ const gemsPromo = { export const EVENTS = { noCurrentEvent: { - start: '2022-04-30T20:00-05:00', + start: '2022-05-31T20:00-04:00', end: '2022-06-30T20:00-05:00', season: 'normal', npcImageSuffix: '', }, + potions202205: { + start: '2022-05-17T08:00-04:00', + end: '2022-05-31T20:00-04:00', + season: 'normal', + npcImageSuffix: '', + }, spring2022: { start: '2022-03-22T08:00-05:00', end: '2022-04-30T20:00-05:00', diff --git a/website/common/script/content/hatching-potions.js b/website/common/script/content/hatching-potions.js index f50ef98f7f..0f7f67d859 100644 --- a/website/common/script/content/hatching-potions.js +++ b/website/common/script/content/hatching-potions.js @@ -96,13 +96,13 @@ const premium = { value: 2, text: t('hatchingPotionFloral'), limited: true, - event: EVENTS.potions202105, + event: EVENTS.potions202205, _addlNotes: t('eventAvailabilityReturning', { availableDate: t('dateEndMay'), - previousDate: t('mayYYYY', { year: 2019 }), + previousDate: t('mayYYYY', { year: 2021 }), }), canBuy () { - return moment().isBefore(EVENTS.potions202105.end); + return moment().isBefore(EVENTS.potions202205.end); }, }, Aquatic: { @@ -297,12 +297,13 @@ const premium = { value: 2, text: t('hatchingPotionSunshine'), limited: true, + event: EVENTS.potions202205, _addlNotes: t('eventAvailabilityReturning', { availableDate: t('dateEndMay'), - previousDate: t('mayYYYY', { year: 2019 }), + previousDate: t('mayYYYY', { year: 2020 }), }), canBuy () { - return moment().isBefore('2020-06-02'); + return moment().isBefore(EVENTS.potions202205.end); }, }, Bronze: { diff --git a/website/common/script/content/shop-featuredItems.js b/website/common/script/content/shop-featuredItems.js index 7cecd12cf3..8d6bb0ec14 100644 --- a/website/common/script/content/shop-featuredItems.js +++ b/website/common/script/content/shop-featuredItems.js @@ -1,11 +1,11 @@ import moment from 'moment'; -import { EVENTS } from './constants'; +// import { EVENTS } from './constants'; // Magic Hatching Potions are configured like this: // type: 'premiumHatchingPotion', // note no "s" at the end // path: 'premiumHatchingPotions.Rainbow', const featuredItems = { market () { - if (moment().isBefore(EVENTS.spring2022.end)) { + if (moment().isBefore('2022-05-31T20:00-04:00')) { return [ { type: 'armoire', @@ -13,15 +13,15 @@ const featuredItems = { }, { type: 'premiumHatchingPotion', - path: 'premiumHatchingPotions.Shimmer', + path: 'premiumHatchingPotions.Sunshine', }, { type: 'premiumHatchingPotion', - path: 'premiumHatchingPotions.Celestial', + path: 'premiumHatchingPotions.Floral', }, { - type: 'premiumHatchingPotion', - path: 'premiumHatchingPotions.PolkaDot', + type: 'hatchingPotions', + path: 'hatchingPotions.Golden', }, ]; } @@ -45,19 +45,19 @@ const featuredItems = { ]; }, quests () { - if (moment().isBefore('2022-03-31T20:00-04:00')) { + if (moment().isBefore('2022-05-31T20:00-04:00')) { return [ { type: 'bundles', - path: 'bundles.cuddleBuddies', + path: 'bundles.delightfulDinos', }, { type: 'quests', - path: 'quests.egg', + path: 'quests.alligator', }, { type: 'quests', - path: 'quests.ghost_stag', + path: 'quests.turtle', }, ]; } From 5a13231027466ca9150b7f8dce6cf53aebfe0ab2 Mon Sep 17 00:00:00 2001 From: SabreCat Date: Tue, 17 May 2022 09:33:34 -0500 Subject: [PATCH 8/8] 4.230.2 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 42ed898b7d..eb6663f175 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "habitica", - "version": "4.230.1", + "version": "4.230.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index b9a6a52518..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.1", + "version": "4.230.2", "main": "./website/server/index.js", "dependencies": { "@babel/core": "^7.17.10",