mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 06:37:23 +01:00
Onboarding guide and initial achievements refactoring (#11536)
* add achievements to user * add placeholder strings * add to achievements to common script * add onboarding achievements category * add notifications * more notifications * award achievements * wip notification panel * add achievements icons and copy * do not count onboarding tasks for the created task achievement * add notes * sprites, fixes and completion status and reward * add onboarding panel * add toggle * fix toggle size * fix tests * fix typo * add notification * start adding modal * fix remove button positionin, timeout, progress bar * modal + fixes * disable broken social links from level up modal * change toggle icon color on hover * add border bottom to onboarding guide panel * add collapse animation * expanded onboarding on first open * onboarding: flip toggle colors * onboarding: show progress bar all the time * onboarding: fix panel closing on click * onboarding modal: add close icon and fix padding * wip: add migration for existing users * fix titles in guide * fix achievements copy * do not award completed task achievement when direction is down * start implementing new achievements * start migrating client * remove social links from achievements modals * prevent skipping tutorial + fix achievement notification * sync fixes * start redesign achievement modal * misc fixes to achievements, polish generic achievement modal and hatched pet modal * add special badge for onboarding * fix badge condition * modals fixes * hatched pet modal: add close icon * fix badge typo * fix justin button * new scrolling behavior for dropdowns * fix strings capitalization * add common tests * add api unit tests * add date check * achievements modal polishing * typos * add toggle for achievements categories * typo * fix test * fix edit avatar modal cannot be closed * finish migration and correct launch date * fix migration * migration fixes * fix tests
This commit is contained in:
@@ -26,10 +26,14 @@
|
||||
<quest-completed />
|
||||
<quest-invitation />
|
||||
<verify-username />
|
||||
<generic-achievement :data="notificationData" />
|
||||
<generic-achievement
|
||||
v-if="notificationData && notificationData.achievement"
|
||||
:data="notificationData"
|
||||
/>
|
||||
<just-add-water />
|
||||
<lost-masterclasser />
|
||||
<mind-over-matter />
|
||||
<onboarding-complete />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -92,6 +96,10 @@
|
||||
background-color: #4f2a93 !important;
|
||||
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.16), 0 1px 4px 0 rgba(26, 24, 29, 0.12) !important;
|
||||
}
|
||||
|
||||
.introjs-skipbutton.btn-primary, .introjs-donebutton.btn-primary {
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
@@ -99,9 +107,11 @@ import axios from 'axios';
|
||||
import moment from 'moment';
|
||||
import throttle from 'lodash/throttle';
|
||||
import debounce from 'lodash/debounce';
|
||||
import Vue from 'vue';
|
||||
|
||||
import { toNextLevel } from '@/../../common/script/statHelpers';
|
||||
import { shouldDo } from '@/../../common/script/cron';
|
||||
import { onOnboardingComplete } from '@/../../common/script/libs/onboarding';
|
||||
import { mapState } from '@/libs/store';
|
||||
import notifications from '@/mixins/notifications';
|
||||
import guide from '@/mixins/guide';
|
||||
@@ -132,6 +142,7 @@ 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';
|
||||
|
||||
const NOTIFICATIONS = {
|
||||
@@ -164,21 +175,33 @@ const NOTIFICATIONS = {
|
||||
achievement: true,
|
||||
label: $t => `${$t('achievement')}: ${$t('achievementAllYourBase')}`,
|
||||
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', // defined manually until the server sends all the necessary data
|
||||
},
|
||||
},
|
||||
ACHIEVEMENT_DUST_DEVIL: {
|
||||
achievement: true,
|
||||
label: $t => `${$t('achievement')}: ${$t('achievementDustDevil')}`,
|
||||
modalId: 'generic-achievement',
|
||||
data: {
|
||||
achievement: 'dustDevil', // defined manually until the server sends all the necessary data
|
||||
},
|
||||
},
|
||||
ACHIEVEMENT_ARID_AUTHORITY: {
|
||||
achievement: true,
|
||||
label: $t => `${$t('achievement')}: ${$t('achievementAridAuthority')}`,
|
||||
modalId: 'generic-achievement',
|
||||
data: {
|
||||
achievement: 'aridAuthority', // defined manually until the server sends all the necessary data
|
||||
},
|
||||
},
|
||||
ACHIEVEMENT_PARTY_UP: {
|
||||
achievement: true,
|
||||
@@ -187,6 +210,7 @@ const NOTIFICATIONS = {
|
||||
data: {
|
||||
message: $t => $t('achievement'),
|
||||
modalText: $t => $t('achievementPartyUp'),
|
||||
achievement: 'partyUp', // defined manually until the server sends all the necessary data
|
||||
},
|
||||
},
|
||||
ACHIEVEMENT_PARTY_ON: {
|
||||
@@ -196,6 +220,7 @@ const NOTIFICATIONS = {
|
||||
data: {
|
||||
message: $t => $t('achievement'),
|
||||
modalText: $t => $t('achievementPartyOn'),
|
||||
achievement: 'partyOn', // defined manually until the server sends all the necessary data
|
||||
},
|
||||
},
|
||||
ACHIEVEMENT_BEAST_MASTER: {
|
||||
@@ -205,6 +230,7 @@ const NOTIFICATIONS = {
|
||||
data: {
|
||||
message: $t => $t('achievement'),
|
||||
modalText: $t => $t('beastAchievement'),
|
||||
achievement: 'beastMaster', // defined manually until the server sends all the necessary data
|
||||
},
|
||||
},
|
||||
ACHIEVEMENT_MOUNT_MASTER: {
|
||||
@@ -214,6 +240,7 @@ const NOTIFICATIONS = {
|
||||
data: {
|
||||
message: $t => $t('achievement'),
|
||||
modalText: $t => $t('mountAchievement'),
|
||||
achievement: 'mountMaster', // defined manually until the server sends all the necessary data
|
||||
},
|
||||
},
|
||||
ACHIEVEMENT_TRIAD_BINGO: {
|
||||
@@ -223,27 +250,49 @@ const NOTIFICATIONS = {
|
||||
data: {
|
||||
message: $t => $t('achievement'),
|
||||
modalText: $t => $t('triadBingoAchievement'),
|
||||
achievement: 'triadBingo', // defined manually until the server sends all the necessary data
|
||||
},
|
||||
},
|
||||
ACHIEVEMENT_MONSTER_MAGUS: {
|
||||
achievement: true,
|
||||
label: $t => `${$t('achievement')}: ${$t('achievementMonsterMagus')}`,
|
||||
modalId: 'generic-achievement',
|
||||
data: {
|
||||
achievement: 'monsterMagus', // defined manually until the server sends all the necessary data
|
||||
},
|
||||
},
|
||||
ACHIEVEMENT_UNDEAD_UNDERTAKER: {
|
||||
achievement: true,
|
||||
label: $t => `${$t('achievement')}: ${$t('achievementUndeadUndertaker')}`,
|
||||
modalId: 'generic-achievement',
|
||||
data: {
|
||||
achievement: 'undeadUndertaker', // defined manually until the server sends all the necessary data
|
||||
},
|
||||
},
|
||||
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', // defined manually until the server sends all the necessary data
|
||||
},
|
||||
},
|
||||
ACHIEVEMENT_PEARLY_PRO: {
|
||||
achievement: true,
|
||||
label: $t => `${$t('achievement')}: ${$t('achievementPearlyPro')}`,
|
||||
modalId: 'generic-achievement',
|
||||
data: {
|
||||
achievement: 'pearlyPro', // defined manually until the server sends all the necessary data
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -276,6 +325,7 @@ export default {
|
||||
lostMasterclasser,
|
||||
mindOverMatter,
|
||||
justAddWater,
|
||||
onboardingComplete,
|
||||
},
|
||||
mixins: [notifications, guide],
|
||||
data () {
|
||||
@@ -302,7 +352,7 @@ export default {
|
||||
'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', 'GENERIC_ACHIEVEMENT',
|
||||
'ACHIEVEMENT_PEARLY_PRO', 'ACHIEVEMENT', 'ONBOARDING_COMPLETE',
|
||||
].forEach(type => {
|
||||
handledNotifications[type] = true;
|
||||
});
|
||||
@@ -478,7 +528,7 @@ export default {
|
||||
this.text(config.label(this.$t), () => {
|
||||
this.notificationData = data;
|
||||
this.$root.$emit('bv::show::modal', config.modalId);
|
||||
}, false);
|
||||
}, true, 10000);
|
||||
}
|
||||
},
|
||||
debounceCheckUserAchievements: debounce(function debounceCheck () {
|
||||
@@ -713,6 +763,18 @@ export default {
|
||||
case 'GENERIC_ACHIEVEMENT':
|
||||
this.showNotificationWithModal(notification);
|
||||
break;
|
||||
case 'ACHIEVEMENT': { // generic achievement
|
||||
const { achievement } = notification.data;
|
||||
const upperCaseAchievement = achievement.charAt(0).toUpperCase() + achievement.slice(1);
|
||||
const achievementTitleKey = `achievement${upperCaseAchievement}`;
|
||||
NOTIFICATIONS.ACHIEVEMENT.label = $t => `${$t('achievement')}: ${$t(achievementTitleKey)}`;
|
||||
NOTIFICATIONS.ACHIEVEMENT.data.modalText = $t => $t(achievementTitleKey);
|
||||
this.showNotificationWithModal(notification);
|
||||
|
||||
// Set the achievement as it's not defined in the user schema
|
||||
Vue.set(this.user.achievements, achievement, true);
|
||||
break;
|
||||
}
|
||||
case 'CRON':
|
||||
if (notification.data) {
|
||||
if (notification.data.hp) this.hp(notification.data.hp, 'hp');
|
||||
@@ -742,6 +804,20 @@ export default {
|
||||
this.$root.$emit('bv::show::modal', 'login-incentives');
|
||||
}
|
||||
break;
|
||||
case 'ONBOARDING_COMPLETE':
|
||||
// Award rewards
|
||||
onOnboardingComplete(this.user);
|
||||
|
||||
// If the user cronned in the last 3 minutes
|
||||
// Don't show too many modals on app load
|
||||
// Use notification panel
|
||||
if (moment().diff(this.user.lastCron, 'minutes') < 3) {
|
||||
markAsRead = false;
|
||||
} else {
|
||||
// Otherwise use the modal
|
||||
this.$root.$emit('bv::show::modal', 'onboarding-complete');
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (markAsRead) notificationsToRead.push(notification.id);
|
||||
|
||||
Reference in New Issue
Block a user