mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 22:57:21 +01:00
Refactor the root App to load less data for front page visits (#15265)
* refactor root app to not load everything when visiting landing page # Conflicts: # website/client/src/app.vue * fix lint * fix hiding loading screen * fix showing snackbars when not logged in * remove console
This commit is contained in:
@@ -27,73 +27,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<snackbars />
|
||||||
id="app"
|
<router-view v-if="!isUserLoggedIn || isStaticPage" />
|
||||||
:class="{
|
<user-main v-else />
|
||||||
'casting-spell': castingSpell,
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<!-- <banned-account-modal /> -->
|
|
||||||
<amazon-payments-modal v-if="!isStaticPage" />
|
|
||||||
<payments-success-modal />
|
|
||||||
<sub-cancel-modal-confirm v-if="isUserLoaded" />
|
|
||||||
<sub-canceled-modal v-if="isUserLoaded" />
|
|
||||||
<bug-report-modal v-if="isUserLoaded" />
|
|
||||||
<bug-report-success-modal v-if="isUserLoaded" />
|
|
||||||
<external-link-modal />
|
|
||||||
<birthday-modal />
|
|
||||||
<snackbars />
|
|
||||||
<router-view v-if="!isUserLoggedIn || isStaticPage" />
|
|
||||||
<template v-else>
|
|
||||||
<template v-if="isUserLoaded">
|
|
||||||
<chat-banner />
|
|
||||||
<damage-paused-banner />
|
|
||||||
<gems-promo-banner />
|
|
||||||
<gift-promo-banner />
|
|
||||||
<birthday-banner />
|
|
||||||
<notifications-display />
|
|
||||||
<app-menu />
|
|
||||||
<div
|
|
||||||
class="container-fluid"
|
|
||||||
:class="{'no-margin': noMargin}"
|
|
||||||
>
|
|
||||||
<app-header />
|
|
||||||
<buyModal
|
|
||||||
:item="selectedItemToBuy || {}"
|
|
||||||
:with-pin="true"
|
|
||||||
:generic-purchase="genericPurchase(selectedItemToBuy)"
|
|
||||||
@buyPressed="customPurchase($event)"
|
|
||||||
/>
|
|
||||||
<selectMembersModal
|
|
||||||
:item="selectedSpellToBuy || {}"
|
|
||||||
:group="user.party"
|
|
||||||
@memberSelected="memberSelected($event)"
|
|
||||||
/>
|
|
||||||
<div :class="{sticky: user.preferences.stickyHeader}">
|
|
||||||
<router-view />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<app-footer v-if="!hideFooter" />
|
|
||||||
<audio
|
|
||||||
id="sound"
|
|
||||||
ref="sound"
|
|
||||||
autoplay="autoplay"
|
|
||||||
></audio>
|
|
||||||
</template>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='scss' scoped>
|
<style lang='scss' scoped>
|
||||||
@import '~@/assets/scss/colors.scss';
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
|
||||||
#app {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
overflow-x: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
#loading-screen-inapp {
|
#loading-screen-inapp {
|
||||||
#melior {
|
#melior {
|
||||||
color: $white;
|
color: $white;
|
||||||
@@ -163,68 +105,20 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { loadProgressBar } from 'axios-progress-bar';
|
|
||||||
|
|
||||||
import birthdayModal from '@/components/news/birthdayModal';
|
|
||||||
import AppMenu from './components/header/menu';
|
|
||||||
import AppHeader from './components/header/index';
|
|
||||||
import ChatBanner from './components/header/banners/chatBanner';
|
|
||||||
import DamagePausedBanner from './components/header/banners/damagePaused';
|
|
||||||
import GemsPromoBanner from './components/header/banners/gemsPromo';
|
|
||||||
import GiftPromoBanner from './components/header/banners/giftPromo';
|
|
||||||
import BirthdayBanner from './components/header/banners/birthdayBanner';
|
|
||||||
import AppFooter from './components/appFooter';
|
|
||||||
import notificationsDisplay from './components/notifications';
|
|
||||||
import snackbars from './components/snackbars/notifications';
|
|
||||||
import { mapState } from '@/libs/store';
|
|
||||||
import * as Analytics from '@/libs/analytics';
|
import * as Analytics from '@/libs/analytics';
|
||||||
import BuyModal from './components/shops/buyModal.vue';
|
import { mapState } from '@/libs/store';
|
||||||
import SelectMembersModal from '@/components/selectMembersModal.vue';
|
import userMain from '@/pages/user-main';
|
||||||
import notifications from '@/mixins/notifications';
|
import snackbars from '@/components/snackbars/notifications';
|
||||||
import { setup as setupPayments } from '@/libs/payments';
|
|
||||||
import amazonPaymentsModal from '@/components/payments/amazonModal';
|
|
||||||
import paymentsSuccessModal from '@/components/payments/successModal';
|
|
||||||
import subCancelModalConfirm from '@/components/payments/cancelModalConfirm';
|
|
||||||
import subCanceledModal from '@/components/payments/canceledModal';
|
|
||||||
import externalLinkModal from '@/components/externalLinkModal.vue';
|
|
||||||
|
|
||||||
import spellsMixin from '@/mixins/spells';
|
|
||||||
import {
|
|
||||||
CONSTANTS,
|
|
||||||
getLocalSetting,
|
|
||||||
removeLocalSetting,
|
|
||||||
} from '@/libs/userlocalManager';
|
|
||||||
|
|
||||||
const bugReportModal = () => import(/* webpackChunkName: "bug-report-modal" */'@/components/bugReportModal');
|
|
||||||
const bugReportSuccessModal = () => import(/* webpackChunkName: "bug-report-success-modal" */'@/components/bugReportSuccessModal');
|
|
||||||
|
|
||||||
const COMMUNITY_MANAGER_EMAIL = process.env.EMAILS_COMMUNITY_MANAGER_EMAIL; // eslint-disable-line
|
const COMMUNITY_MANAGER_EMAIL = process.env.EMAILS_COMMUNITY_MANAGER_EMAIL; // eslint-disable-line
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
components: {
|
components: {
|
||||||
AppMenu,
|
|
||||||
AppHeader,
|
|
||||||
AppFooter,
|
|
||||||
birthdayModal,
|
|
||||||
ChatBanner,
|
|
||||||
DamagePausedBanner,
|
|
||||||
GemsPromoBanner,
|
|
||||||
GiftPromoBanner,
|
|
||||||
BirthdayBanner,
|
|
||||||
notificationsDisplay,
|
|
||||||
snackbars,
|
snackbars,
|
||||||
BuyModal,
|
userMain,
|
||||||
SelectMembersModal,
|
|
||||||
amazonPaymentsModal,
|
|
||||||
paymentsSuccessModal,
|
|
||||||
subCancelModalConfirm,
|
|
||||||
subCanceledModal,
|
|
||||||
bugReportModal,
|
|
||||||
bugReportSuccessModal,
|
|
||||||
externalLinkModal,
|
|
||||||
},
|
},
|
||||||
mixins: [notifications, spellsMixin],
|
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
selectedItemToBuy: null,
|
selectedItemToBuy: null,
|
||||||
@@ -238,71 +132,24 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState(['isUserLoggedIn', 'browserTimezoneUtcOffset', 'isUserLoaded', 'notificationsRemoved']),
|
...mapState(['isUserLoggedIn', 'isUserLoaded']),
|
||||||
...mapState({ user: 'user.data' }),
|
|
||||||
isStaticPage () {
|
isStaticPage () {
|
||||||
return this.$route.meta.requiresLogin === false;
|
return this.$route.meta.requiresLogin === false;
|
||||||
},
|
},
|
||||||
castingSpell () {
|
|
||||||
return this.$store.state.spellOptions.castingSpell;
|
|
||||||
},
|
|
||||||
noMargin () {
|
|
||||||
return ['privateMessages'].includes(this.$route.name);
|
|
||||||
},
|
|
||||||
hideFooter () {
|
|
||||||
return ['privateMessages'].includes(this.$route.name);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
this.$root.$on('playSound', sound => {
|
// Setup listener for title
|
||||||
const theme = this.user.preferences.sound;
|
this.$store.watch(state => state.title, title => {
|
||||||
|
document.title = title;
|
||||||
if (!theme || theme === 'off') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const file = `/static/audio/${theme}/${sound}`;
|
|
||||||
|
|
||||||
if (this.audioSuffix === null) {
|
|
||||||
this.audioSource = document.createElement('source');
|
|
||||||
if (this.$refs.sound.canPlayType('audio/ogg')) {
|
|
||||||
this.audioSuffix = '.ogg';
|
|
||||||
this.audioSource.type = 'audio/ogg';
|
|
||||||
} else {
|
|
||||||
this.audioSuffix = '.mp3';
|
|
||||||
this.audioSource.type = 'audio/mp3';
|
|
||||||
}
|
|
||||||
this.audioSource.src = file + this.audioSuffix;
|
|
||||||
this.$refs.sound.appendChild(this.audioSource);
|
|
||||||
} else {
|
|
||||||
this.audioSource.src = file + this.audioSuffix;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$refs.sound.load();
|
|
||||||
});
|
});
|
||||||
|
this.$store.watch(state => state.isUserLoaded, () => {
|
||||||
// @TODO: I'm not sure these should be at the app level.
|
if (this.isUserLoaded) {
|
||||||
// Can we move these back into shop/inventory or maybe they need a lateral move?
|
this.hideLoadingScreen();
|
||||||
this.$root.$on('buyModal::showItem', item => {
|
|
||||||
this.selectedItemToBuy = item;
|
|
||||||
this.$root.$emit('bv::show::modal', 'buy-modal');
|
|
||||||
});
|
|
||||||
|
|
||||||
this.$root.$on('bv::modal::hidden', event => {
|
|
||||||
if (event.componentId === 'buy-modal') {
|
|
||||||
this.$root.$emit('buyModal::hidden', this.selectedItemToBuy.key);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
this.$nextTick(() => {
|
||||||
this.$root.$on('selectMembersModal::showItem', item => {
|
// Load external scripts after the app has been rendered
|
||||||
this.selectedSpellToBuy = item;
|
Analytics.load();
|
||||||
this.$root.$emit('bv::show::modal', 'select-member-modal');
|
|
||||||
});
|
|
||||||
|
|
||||||
// @TODO split up this file, it's too big
|
|
||||||
|
|
||||||
loadProgressBar({
|
|
||||||
showSpinner: false,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
axios.interceptors.response.use(response => { // Set up Response interceptors
|
axios.interceptors.response.use(response => { // Set up Response interceptors
|
||||||
@@ -414,79 +261,20 @@ export default {
|
|||||||
|
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Setup listener for title
|
|
||||||
this.$store.watch(state => state.title, title => {
|
|
||||||
document.title = title;
|
|
||||||
});
|
|
||||||
this.$nextTick(() => {
|
|
||||||
// Load external scripts after the app has been rendered
|
|
||||||
Analytics.load();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (this.isUserLoggedIn && !this.isStaticPage) {
|
|
||||||
// Load the user and the user tasks
|
|
||||||
Promise.all([
|
|
||||||
this.$store.dispatch('user:fetch'),
|
|
||||||
this.$store.dispatch('tasks:fetchUserTasks'),
|
|
||||||
]).then(() => {
|
|
||||||
this.$store.state.isUserLoaded = true;
|
|
||||||
Analytics.setUser();
|
|
||||||
Analytics.updateUser();
|
|
||||||
return axios.get(
|
|
||||||
'/api/v4/i18n/browser-script',
|
|
||||||
{
|
|
||||||
language: this.user.preferences.language,
|
|
||||||
headers: {
|
|
||||||
'Cache-Control': 'no-cache',
|
|
||||||
Pragma: 'no-cache',
|
|
||||||
Expires: '0',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}).then(() => {
|
|
||||||
const i18nData = window && window['habitica-i18n'];
|
|
||||||
this.$loadLocale(i18nData);
|
|
||||||
this.hideLoadingScreen();
|
|
||||||
|
|
||||||
// Adjust the timezone offset
|
|
||||||
const browserTimezoneOffset = -this.browserTimezoneUtcOffset;
|
|
||||||
if (this.user.preferences.timezoneOffset !== browserTimezoneOffset) {
|
|
||||||
this.$store.dispatch('user:set', {
|
|
||||||
'preferences.timezoneOffset': browserTimezoneOffset,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let appState = getLocalSetting(CONSTANTS.savedAppStateValues.SAVED_APP_STATE);
|
|
||||||
if (appState) {
|
|
||||||
appState = JSON.parse(appState);
|
|
||||||
if (appState.paymentCompleted) {
|
|
||||||
removeLocalSetting(CONSTANTS.savedAppStateValues.SAVED_APP_STATE);
|
|
||||||
this.$root.$emit('habitica:payment-success', appState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.$nextTick(() => {
|
|
||||||
// Load external scripts after the app has been rendered
|
|
||||||
setupPayments();
|
|
||||||
});
|
|
||||||
}).catch(err => {
|
|
||||||
console.error('Impossible to fetch user. Clean up localStorage and refresh.', err); // eslint-disable-line no-console
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.hideLoadingScreen();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
beforeDestroy () {
|
|
||||||
this.$root.$off('playSound');
|
|
||||||
this.$root.$off('buyModal::showItem');
|
|
||||||
this.$root.$off('selectMembersModal::showItem');
|
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
// Remove the index.html loading screen and now show the inapp loading
|
// Remove the index.html loading screen and now show the inapp loading
|
||||||
const loadingScreen = document.getElementById('loading-screen');
|
const loadingScreen = document.getElementById('loading-screen');
|
||||||
if (loadingScreen) document.body.removeChild(loadingScreen);
|
if (loadingScreen) document.body.removeChild(loadingScreen);
|
||||||
|
|
||||||
|
if (this.isStaticPage || !this.isUserLoggedIn) {
|
||||||
|
this.hideLoadingScreen();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
hideLoadingScreen () {
|
||||||
|
this.loading = false;
|
||||||
|
},
|
||||||
checkForBannedUser (error) {
|
checkForBannedUser (error) {
|
||||||
const AUTH_SETTINGS = localStorage.getItem('habit-mobile-settings');
|
const AUTH_SETTINGS = localStorage.getItem('habit-mobile-settings');
|
||||||
const parseSettings = JSON.parse(AUTH_SETTINGS);
|
const parseSettings = JSON.parse(AUTH_SETTINGS);
|
||||||
@@ -507,57 +295,10 @@ export default {
|
|||||||
this.$store.dispatch('auth:logout', { redirectToLogin: true });
|
this.$store.dispatch('auth:logout', { redirectToLogin: true });
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
itemSelected (item) {
|
|
||||||
this.selectedItemToBuy = item;
|
|
||||||
},
|
|
||||||
genericPurchase (item) {
|
|
||||||
if (!item) return false;
|
|
||||||
|
|
||||||
if (['card', 'debuffPotion'].includes(item.purchaseType)) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
customPurchase (item) {
|
|
||||||
if (item.purchaseType === 'card') {
|
|
||||||
this.selectedSpellToBuy = item;
|
|
||||||
|
|
||||||
// hide the dialog
|
|
||||||
this.$root.$emit('bv::hide::modal', 'buy-modal');
|
|
||||||
// remove the dialog from our modal-stack,
|
|
||||||
// the default hidden event is delayed
|
|
||||||
this.$root.$emit('bv::modal::hidden', {
|
|
||||||
target: {
|
|
||||||
id: 'buy-modal',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
this.$root.$emit('bv::show::modal', 'select-member-modal');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.purchaseType === 'debuffPotion') {
|
|
||||||
this.castStart(item, this.user);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async memberSelected (member) {
|
|
||||||
await this.castStart(this.selectedSpellToBuy, member);
|
|
||||||
|
|
||||||
this.selectedSpellToBuy = null;
|
|
||||||
|
|
||||||
if (this.user.party._id) {
|
|
||||||
this.$store.dispatch('party:getMembers', { forceLoad: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$root.$emit('bv::hide::modal', 'select-member-modal');
|
|
||||||
},
|
|
||||||
hideLoadingScreen () {
|
|
||||||
this.loading = false;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style src="intro.js/minified/introjs.min.css"></style>
|
|
||||||
<style src="axios-progress-bar/dist/nprogress.css"></style>
|
|
||||||
<style src="@/assets/scss/index.scss" lang="scss"></style>
|
<style src="@/assets/scss/index.scss" lang="scss"></style>
|
||||||
<style src="@/assets/scss/sprites.scss" lang="scss"></style>
|
<style src="@/assets/scss/sprites.scss" lang="scss"></style>
|
||||||
<style src="smartbanner.js/dist/smartbanner.min.css"></style>
|
<style src="smartbanner.js/dist/smartbanner.min.css"></style>
|
||||||
|
|||||||
@@ -16,10 +16,10 @@
|
|||||||
class="brand"
|
class="brand"
|
||||||
aria-label="Habitica"
|
aria-label="Habitica"
|
||||||
>
|
>
|
||||||
<router-link to="/">
|
<router-link to="/">
|
||||||
<div
|
<div
|
||||||
class="logo svg-icon svg color gryphon pl-2 mr-3"
|
class="logo svg-icon svg color gryphon pl-2 mr-3"
|
||||||
v-html="icons.melior"
|
v-html="icons.melior"
|
||||||
></div>
|
></div>
|
||||||
<div class="svg-icon"></div>
|
<div class="svg-icon"></div>
|
||||||
</router-link>
|
</router-link>
|
||||||
|
|||||||
383
website/client/src/pages/user-main.vue
Normal file
383
website/client/src/pages/user-main.vue
Normal file
@@ -0,0 +1,383 @@
|
|||||||
|
<template>
|
||||||
|
<div
|
||||||
|
id="app"
|
||||||
|
:class="{
|
||||||
|
'casting-spell': castingSpell,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<!-- <banned-account-modal /> -->
|
||||||
|
<amazon-payments-modal v-if="!isStaticPage" />
|
||||||
|
<payments-success-modal />
|
||||||
|
<sub-cancel-modal-confirm v-if="isUserLoaded" />
|
||||||
|
<sub-canceled-modal v-if="isUserLoaded" />
|
||||||
|
<bug-report-modal v-if="isUserLoaded" />
|
||||||
|
<bug-report-success-modal v-if="isUserLoaded" />
|
||||||
|
<external-link-modal />
|
||||||
|
<birthday-modal />
|
||||||
|
<template v-if="isUserLoaded">
|
||||||
|
<chat-banner />
|
||||||
|
<damage-paused-banner />
|
||||||
|
<gems-promo-banner />
|
||||||
|
<gift-promo-banner />
|
||||||
|
<birthday-banner />
|
||||||
|
<notifications-display />
|
||||||
|
<app-menu />
|
||||||
|
<div
|
||||||
|
class="container-fluid"
|
||||||
|
:class="{'no-margin': noMargin}"
|
||||||
|
>
|
||||||
|
<app-header />
|
||||||
|
<buyModal
|
||||||
|
:item="selectedItemToBuy || {}"
|
||||||
|
:with-pin="true"
|
||||||
|
:generic-purchase="genericPurchase(selectedItemToBuy)"
|
||||||
|
@buyPressed="customPurchase($event)"
|
||||||
|
/>
|
||||||
|
<selectMembersModal
|
||||||
|
:item="selectedSpellToBuy || {}"
|
||||||
|
:group="user.party"
|
||||||
|
@memberSelected="memberSelected($event)"
|
||||||
|
/>
|
||||||
|
<div :class="{sticky: user.preferences.stickyHeader}">
|
||||||
|
<router-view />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<app-footer v-if="!hideFooter" />
|
||||||
|
<audio
|
||||||
|
id="sound"
|
||||||
|
ref="sound"
|
||||||
|
autoplay="autoplay"
|
||||||
|
></audio>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang='scss' scoped>
|
||||||
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
|
||||||
|
#app {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.casting-spell {
|
||||||
|
cursor: crosshair;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container-fluid {
|
||||||
|
flex: 1 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-margin {
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification {
|
||||||
|
border-radius: 1000px;
|
||||||
|
background-color: $green-10;
|
||||||
|
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.16), 0 1px 4px 0 rgba(26, 24, 29, 0.12);
|
||||||
|
padding: .5em 1em;
|
||||||
|
color: $white;
|
||||||
|
margin-top: .5em;
|
||||||
|
margin-bottom: .5em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang='scss'>
|
||||||
|
@import '~@/assets/scss/colors.scss';
|
||||||
|
|
||||||
|
.modal-backdrop {
|
||||||
|
opacity: .9 !important;
|
||||||
|
background-color: $purple-100 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Push progress bar above modals */
|
||||||
|
#nprogress .bar {
|
||||||
|
z-index: 1600 !important; /* Must stay above nav bar */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from 'axios';
|
||||||
|
import { loadProgressBar } from 'axios-progress-bar';
|
||||||
|
|
||||||
|
import birthdayModal from '@/components/news/birthdayModal';
|
||||||
|
import AppMenu from '@/components/header/menu';
|
||||||
|
import AppHeader from '@/components/header/index';
|
||||||
|
import ChatBanner from '@/components/header/banners/chatBanner';
|
||||||
|
import DamagePausedBanner from '@/components/header/banners/damagePaused';
|
||||||
|
import GemsPromoBanner from '@/components/header/banners/gemsPromo';
|
||||||
|
import GiftPromoBanner from '@/components/header/banners/giftPromo';
|
||||||
|
import BirthdayBanner from '@/components/header/banners/birthdayBanner';
|
||||||
|
import AppFooter from '@/components/appFooter';
|
||||||
|
import notificationsDisplay from '@/components/notifications';
|
||||||
|
import { mapState } from '@/libs/store';
|
||||||
|
import * as Analytics from '@/libs/analytics';
|
||||||
|
import BuyModal from '@/components/shops/buyModal.vue';
|
||||||
|
import SelectMembersModal from '@/components/selectMembersModal.vue';
|
||||||
|
import notifications from '@/mixins/notifications';
|
||||||
|
import { setup as setupPayments } from '@/libs/payments';
|
||||||
|
import amazonPaymentsModal from '@/components/payments/amazonModal';
|
||||||
|
import paymentsSuccessModal from '@/components/payments/successModal';
|
||||||
|
import subCancelModalConfirm from '@/components/payments/cancelModalConfirm';
|
||||||
|
import subCanceledModal from '@/components/payments/canceledModal';
|
||||||
|
import externalLinkModal from '@/components/externalLinkModal.vue';
|
||||||
|
|
||||||
|
import spellsMixin from '@/mixins/spells';
|
||||||
|
import {
|
||||||
|
CONSTANTS,
|
||||||
|
getLocalSetting,
|
||||||
|
removeLocalSetting,
|
||||||
|
} from '@/libs/userlocalManager';
|
||||||
|
|
||||||
|
const bugReportModal = () => import(/* webpackChunkName: "bug-report-modal" */'@/components/bugReportModal');
|
||||||
|
const bugReportSuccessModal = () => import(/* webpackChunkName: "bug-report-success-modal" */'@/components/bugReportSuccessModal');
|
||||||
|
|
||||||
|
const COMMUNITY_MANAGER_EMAIL = process.env.EMAILS_COMMUNITY_MANAGER_EMAIL; // eslint-disable-line
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'App',
|
||||||
|
components: {
|
||||||
|
AppMenu,
|
||||||
|
AppHeader,
|
||||||
|
AppFooter,
|
||||||
|
birthdayModal,
|
||||||
|
ChatBanner,
|
||||||
|
DamagePausedBanner,
|
||||||
|
GemsPromoBanner,
|
||||||
|
GiftPromoBanner,
|
||||||
|
BirthdayBanner,
|
||||||
|
notificationsDisplay,
|
||||||
|
BuyModal,
|
||||||
|
SelectMembersModal,
|
||||||
|
amazonPaymentsModal,
|
||||||
|
paymentsSuccessModal,
|
||||||
|
subCancelModalConfirm,
|
||||||
|
subCanceledModal,
|
||||||
|
bugReportModal,
|
||||||
|
bugReportSuccessModal,
|
||||||
|
externalLinkModal,
|
||||||
|
},
|
||||||
|
mixins: [notifications, spellsMixin],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
selectedItemToBuy: null,
|
||||||
|
selectedSpellToBuy: null,
|
||||||
|
|
||||||
|
audioSource: null,
|
||||||
|
audioSuffix: null,
|
||||||
|
|
||||||
|
loading: true,
|
||||||
|
bannerHidden: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
...mapState(['isUserLoggedIn', 'browserTimezoneUtcOffset', 'isUserLoaded', 'notificationsRemoved']),
|
||||||
|
...mapState({ user: 'user.data' }),
|
||||||
|
isStaticPage () {
|
||||||
|
return this.$route.meta.requiresLogin === false;
|
||||||
|
},
|
||||||
|
castingSpell () {
|
||||||
|
return this.$store.state.spellOptions.castingSpell;
|
||||||
|
},
|
||||||
|
noMargin () {
|
||||||
|
return ['privateMessages'].includes(this.$route.name);
|
||||||
|
},
|
||||||
|
hideFooter () {
|
||||||
|
return ['privateMessages'].includes(this.$route.name);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.$root.$on('playSound', sound => {
|
||||||
|
const theme = this.user.preferences.sound;
|
||||||
|
|
||||||
|
if (!theme || theme === 'off') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const file = `/static/audio/${theme}/${sound}`;
|
||||||
|
|
||||||
|
if (this.audioSuffix === null) {
|
||||||
|
this.audioSource = document.createElement('source');
|
||||||
|
if (this.$refs.sound.canPlayType('audio/ogg')) {
|
||||||
|
this.audioSuffix = '.ogg';
|
||||||
|
this.audioSource.type = 'audio/ogg';
|
||||||
|
} else {
|
||||||
|
this.audioSuffix = '.mp3';
|
||||||
|
this.audioSource.type = 'audio/mp3';
|
||||||
|
}
|
||||||
|
this.audioSource.src = file + this.audioSuffix;
|
||||||
|
this.$refs.sound.appendChild(this.audioSource);
|
||||||
|
} else {
|
||||||
|
this.audioSource.src = file + this.audioSuffix;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$refs.sound.load();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$root.$on('buyModal::showItem', item => {
|
||||||
|
this.selectedItemToBuy = item;
|
||||||
|
this.$root.$emit('bv::show::modal', 'buy-modal');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$root.$on('bv::modal::hidden', event => {
|
||||||
|
if (event.componentId === 'buy-modal') {
|
||||||
|
this.$root.$emit('buyModal::hidden', this.selectedItemToBuy.key);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$root.$on('selectMembersModal::showItem', item => {
|
||||||
|
this.selectedSpellToBuy = item;
|
||||||
|
this.$root.$emit('bv::show::modal', 'select-member-modal');
|
||||||
|
});
|
||||||
|
|
||||||
|
// @TODO split up this file, it's too big
|
||||||
|
|
||||||
|
loadProgressBar({
|
||||||
|
showSpinner: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Setup listener for title
|
||||||
|
this.$store.watch(state => state.title, title => {
|
||||||
|
document.title = title;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load the user and the user tasks
|
||||||
|
Promise.all([
|
||||||
|
this.$store.dispatch('user:fetch'),
|
||||||
|
this.$store.dispatch('tasks:fetchUserTasks'),
|
||||||
|
]).then(() => {
|
||||||
|
this.$store.state.isUserLoaded = true;
|
||||||
|
Analytics.setUser();
|
||||||
|
Analytics.updateUser();
|
||||||
|
if (window && window['habitica-i18n']) {
|
||||||
|
if (this.user.preferences.language === window['habitica-i18n'].language.code) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return axios.get(
|
||||||
|
'/api/v4/i18n/browser-script',
|
||||||
|
{
|
||||||
|
language: this.user.preferences.language,
|
||||||
|
headers: {
|
||||||
|
'Cache-Control': 'no-cache',
|
||||||
|
Pragma: 'no-cache',
|
||||||
|
Expires: '0',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}).then(() => {
|
||||||
|
const i18nData = window && window['habitica-i18n'];
|
||||||
|
this.$loadLocale(i18nData);
|
||||||
|
this.hideLoadingScreen();
|
||||||
|
|
||||||
|
// Adjust the timezone offset
|
||||||
|
const browserTimezoneOffset = -this.browserTimezoneUtcOffset;
|
||||||
|
if (this.user.preferences.timezoneOffset !== browserTimezoneOffset) {
|
||||||
|
this.$store.dispatch('user:set', {
|
||||||
|
'preferences.timezoneOffset': browserTimezoneOffset,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let appState = getLocalSetting(CONSTANTS.savedAppStateValues.SAVED_APP_STATE);
|
||||||
|
if (appState) {
|
||||||
|
appState = JSON.parse(appState);
|
||||||
|
if (appState.paymentCompleted) {
|
||||||
|
removeLocalSetting(CONSTANTS.savedAppStateValues.SAVED_APP_STATE);
|
||||||
|
this.$root.$emit('habitica:payment-success', appState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.$nextTick(() => {
|
||||||
|
// Load external scripts after the app has been rendered
|
||||||
|
setupPayments();
|
||||||
|
});
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('Impossible to fetch user. Clean up localStorage and refresh.', err); // eslint-disable-line no-console
|
||||||
|
});
|
||||||
|
},
|
||||||
|
beforeDestroy () {
|
||||||
|
this.$root.$off('playSound');
|
||||||
|
this.$root.$off('buyModal::showItem');
|
||||||
|
this.$root.$off('selectMembersModal::showItem');
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
// Remove the index.html loading screen and now show the inapp loading
|
||||||
|
const loadingScreen = document.getElementById('loading-screen');
|
||||||
|
if (loadingScreen) document.body.removeChild(loadingScreen);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
checkForBannedUser (error) {
|
||||||
|
const AUTH_SETTINGS = localStorage.getItem('habit-mobile-settings');
|
||||||
|
const parseSettings = JSON.parse(AUTH_SETTINGS);
|
||||||
|
const errorMessage = error.response.data.message;
|
||||||
|
|
||||||
|
// Case where user is not logged in
|
||||||
|
if (!parseSettings) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bannedMessage = this.$t('accountSuspended', {
|
||||||
|
communityManagerEmail: COMMUNITY_MANAGER_EMAIL,
|
||||||
|
userId: parseSettings.auth.apiId,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (errorMessage !== bannedMessage) return false;
|
||||||
|
|
||||||
|
this.$store.dispatch('auth:logout', { redirectToLogin: true });
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
itemSelected (item) {
|
||||||
|
this.selectedItemToBuy = item;
|
||||||
|
},
|
||||||
|
genericPurchase (item) {
|
||||||
|
if (!item) return false;
|
||||||
|
|
||||||
|
if (['card', 'debuffPotion'].includes(item.purchaseType)) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
customPurchase (item) {
|
||||||
|
if (item.purchaseType === 'card') {
|
||||||
|
this.selectedSpellToBuy = item;
|
||||||
|
|
||||||
|
// hide the dialog
|
||||||
|
this.$root.$emit('bv::hide::modal', 'buy-modal');
|
||||||
|
// remove the dialog from our modal-stack,
|
||||||
|
// the default hidden event is delayed
|
||||||
|
this.$root.$emit('bv::modal::hidden', {
|
||||||
|
target: {
|
||||||
|
id: 'buy-modal',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$root.$emit('bv::show::modal', 'select-member-modal');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.purchaseType === 'debuffPotion') {
|
||||||
|
this.castStart(item, this.user);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async memberSelected (member) {
|
||||||
|
await this.castStart(this.selectedSpellToBuy, member);
|
||||||
|
|
||||||
|
this.selectedSpellToBuy = null;
|
||||||
|
|
||||||
|
if (this.user.party._id) {
|
||||||
|
this.$store.dispatch('party:getMembers', { forceLoad: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$root.$emit('bv::hide::modal', 'select-member-modal');
|
||||||
|
},
|
||||||
|
hideLoadingScreen () {
|
||||||
|
this.loading = false;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style src="intro.js/minified/introjs.min.css"></style>
|
||||||
|
<style src="axios-progress-bar/dist/nprogress.css"></style>
|
||||||
Reference in New Issue
Block a user