Revert "#12781 Add a unified component for small modals (#12987)"

This reverts commit 591c9bc98c.
This commit is contained in:
Sabe Jones 2021-05-06 14:18:31 -05:00
parent ec3c319059
commit 833e2b195d
11 changed files with 699 additions and 673 deletions

View file

@ -1,5 +1,3 @@
@import '~@/assets/scss/colors.scss';
@mixin centeredModal() {
display: flex;
justify-content: center;
@ -8,58 +6,4 @@
header, footer {
border: 0;
}
}
@mixin smallModal() {
.modal-content {
border-radius: 8px;
box-shadow: 0 14px 28px 0 rgba($black, 0.24), 0 10px 10px 0 rgba($black, 0.28);
}
@media (min-width: 576px) {
max-width: 20.625rem;
}
header {
padding: 0;
border: none;
h5 {
margin: 2rem auto 1rem;
color: $purple-200;
}
button {
position: absolute;
right: 18px;
top: 12px;
font-weight: 100;
}
}
footer {
padding: 0;
border: none;
button {
margin: 0 auto 2rem;
}
}
.greyed {
background-color: $gray-700;
}
.modal-body {
padding: 0;
}
.modal-text {
margin: 1.5rem;
min-height: auto !important;
}
footer.greyed {
padding: 0 1.5rem 1rem;
}
}

View file

@ -1,63 +1,135 @@
<template>
<small-modal
<b-modal
id="drop-cap-reached"
:title="$t('dropCapReached')"
button-text-key="learnMore"
@buttonClicked="toLearnMore"
size="md"
:hide-header="true"
:hide-footer="hasSubscription"
>
<starred>
<div class="max-items-module d-flex align-items-center justify-content-center flex-column">
<h1 class="max-items">
{{ maxItems }}
</h1>
<span
<div class="text-center">
<div
class="modal-close"
@click="close()"
>
<div
v-once
class="items-text"
>{{ $t('items') }}</span>
class="svg-icon"
v-html="icons.close"
></div>
</div>
</starred>
<p v-once class="text-center m-3">
{{ $t('dropCapExplanation') }}
</p>
<a
v-once
class="standard-link d-block mb-3 text-center"
@click="toWiki"
<h1
v-once
class="header purple"
>
{{ $t('dropCapReached') }}
</h1>
<div class="max-items-wrapper d-flex align-items-center justify-content-center">
<div
class="svg-icon sparkles sparkles-rotate"
v-html="icons.sparkles"
></div>
<div class="max-items-module d-flex align-items-center justify-content-center flex-column">
<h1 class="max-items">
{{ maxItems }}
</h1>
<span
v-once
class="items-text"
>{{ $t('items') }}</span>
</div>
<div
class="svg-icon sparkles"
v-html="icons.sparkles"
></div>
</div>
<p
v-once
class="mb-4"
>
{{ $t('dropCapExplanation') }}
</p>
<a
v-once
class="standard-link d-block mb-3"
@click="toWiki()"
>
{{ $t('dropCapLearnMore') }}
</a>
</div>
<div
slot="modal-footer"
class="footer"
>
{{ $t('dropCapLearnMore') }}
</a>
<template #greyed>
<div class="text-center">
<span
v-once
class="purple d-block font-weight-bold mb-3 mt-3"
>
{{ $t('lookingForMoreItems') }}
</span>
<img
class="swords mb-3"
srcset="
~@/assets/images/swords.png,
~@/assets/images/swords@2x.png 2x,
~@/assets/images/swords@3x.png 3x"
src="~@/assets/images/swords.png"
>
<p
v-once
class="subs-benefits mb-0"
>
{{ $t('dropCapSubs') }}
</p>
</div>
</template>
</small-modal>
<span
v-once
class="purple d-block font-weight-bold mb-3 mt-3"
>
{{ $t('lookingForMoreItems') }}
</span>
<img
class="swords mb-3"
srcset="
~@/assets/images/swords.png,
~@/assets/images/swords@2x.png 2x,
~@/assets/images/swords@3x.png 3x"
src="~@/assets/images/swords.png"
>
<p
v-once
class="subs-benefits mb-3"
>
{{ $t('dropCapSubs') }}
</p>
<button
v-once
class="btn btn-primary"
@click="toLearnMore()"
>
{{ $t('learnMore') }}
</button>
</div>
</b-modal>
</template>
<style lang="scss">
@import '~@/assets/scss/colors.scss';
#drop-cap-reached {
.modal-body {
padding: 0 1.5rem;
}
.modal-footer {
background: $gray-700;
border-top: none;
padding: 0 1.5rem 2rem 1.5rem;
}
.modal-dialog {
width: 20.625rem;
font-size: 0.875rem;
line-height: 1.71;
text-align: center;
}
}
</style>
<style lang="scss" scoped>
@import '~@/assets/scss/colors.scss';
.modal-close {
position: absolute;
width: 18px;
height: 18px;
padding: 4px;
right: 16px;
top: 16px;
cursor: pointer;
.svg-icon {
width: 12px;
height: 12px;
}
}
.subs-benefits {
font-size: 0.75rem;
line-height: 1.33;
@ -68,6 +140,22 @@
color: $purple-300;
}
.header {
font-size: 1.25rem;
line-height: 1.4;
text-align: center;
margin-top: 2rem;
}
.sparkles {
width: 2.5rem;
height: 4rem;
&.sparkles-rotate {
transform: rotate(180deg);
}
}
.max-items-wrapper {
margin: 17px auto;
}
@ -102,19 +190,20 @@
</style>
<script>
import smallModal from '@/components/ui/modal/smallModal';
import starred from '@/components/ui/modal/starred.vue';
import closeIcon from '@/assets/svg/close.svg';
import sparkles from '@/assets/svg/star-group.svg';
import * as Analytics from '@/libs/analytics';
import { mapState } from '@/libs/store';
export default {
components: {
smallModal,
starred,
},
data () {
return { maxItems: null };
return {
icons: Object.freeze({
close: closeIcon,
sparkles,
}),
maxItems: null,
};
},
computed: {
...mapState({ user: 'user.data' }),
@ -132,6 +221,9 @@ export default {
this.$root.$off('habitica:drop-cap-reached');
},
methods: {
close () {
this.$root.$emit('bv::hide::modal', 'drop-cap-reached');
},
toWiki () {
window.open('https://habitica.fandom.com/wiki/Drops', '_blank');
@ -150,7 +242,7 @@ export default {
eventLabel: 'Drop Cap Reached > Modal > Subscriptions',
});
this.$root.$emit('bv::hide::modal', 'drop-cap-reached');
this.close();
this.$router.push('/user/settings/subscription');
},
},

View file

@ -1,45 +1,167 @@
<template>
<small-modal id="level-up" :title="title">
<starred>
<b-modal
id="level-up"
size="sm"
:title="title"
ok-only
:ok-title="$t('onwards')"
:footer-class="{ greyed: displayRewardQuest }"
>
<section class="d-flex">
<span
class="star-group mirror"
v-html="icons.starGroup"
></span>
<avatar
class="avatar"
:member="user"
hide-class-badge
/>
</starred>
<span
class="star-group"
v-html="icons.starGroup"
></span>
</section>
<p class="text">{{ $t('levelup') }}</p>
<p
v-once
class="text"
>
{{ $t('levelup') }}
</p>
<template #greyed>
<div v-if="displayRewardQuest">
<your-rewards />
<div :class="questClass"></div>
<section
v-if="displayRewardQuest"
class="greyed"
>
<div
v-once
class="your-rewards d-flex"
>
<span
class="sparkles"
v-html="icons.sparkles"
></span>
<span class="text">{{ $t('yourRewards') }}</span>
<span
class="sparkles mirror"
v-html="icons.sparkles"
></span>
</div>
</template>
</small-modal>
<div :class="questClass"></div>
</section>
<!-- @TODO: Keep this? .checkboxinput(type='checkbox', v-model=
'user.preferences.suppressModals.levelUp', @change='changeLevelupSuppress()')
label(style='display:inline-block') {{ $t('dontShowAgain') }}
-->
</b-modal>
</template>
<style lang="scss">
.avatar {
cursor: auto;
}
@import '~@/assets/scss/colors.scss';
.text {
margin: 1rem;
}
#level-up {
.modal-content {
border-radius: 8px;
box-shadow: 0 14px 28px 0 rgba($black, 0.24), 0 10px 10px 0 rgba($black, 0.28);
}
.scroll {
margin: -11px auto 0;
@media (min-width: 576px) {
.modal-sm {
max-width: 330px;
}
}
header {
padding: 0;
border: none;
h5 {
margin: 31px auto 16px;
color: $purple-200;
}
button {
position: absolute;
right: 18px;
top: 12px;
}
}
footer {
padding: 0;
border: none;
button {
margin: 0 auto 32px auto;
}
}
.greyed {
background-color: $gray-700;
}
.modal-body {
padding: 0;
}
.mirror {
transform: scaleX(-1);
}
.star-group {
margin: auto;
svg {
height: 64px;
width: 40px;
}
}
.avatar {
cursor: auto;
}
.class-badge {
display: none !important;
}
.text {
margin: 25px 24px 24px;
min-height: auto;
}
.your-rewards {
margin: 0 auto;
width: fit-content;
.sparkles {
width: 32px;
margin-top: 12px;
}
.text {
font-weight: bold;
margin: 16px;
color: $gray-50;
}
}
section.greyed {
padding-bottom: 17px
}
.scroll {
margin: -11px auto 0;
}
}
</style>
<script>
import Avatar from '../avatar';
import { mapState } from '@/libs/store';
import Avatar from '@/components/avatar';
import smallModal from '@/components/ui/modal/smallModal';
import starred from '@/components/ui/modal/starred.vue';
import yourRewards from '@/components/ui/modal/your-rewards.vue';
import starGroup from '@/assets/svg/star-group.svg';
import sparkles from '@/assets/svg/sparkles-left.svg';
const levelQuests = {
15: 'atom1',
@ -51,9 +173,14 @@ const levelQuests = {
export default {
components: {
Avatar,
smallModal,
starred,
yourRewards,
},
data () {
return {
icons: Object.freeze({
starGroup,
sparkles,
}),
};
},
computed: {
...mapState({ user: 'user.data' }),
@ -67,5 +194,11 @@ export default {
return `scroll inventory_quest_scroll_${levelQuests[this.user.stats.lvl]}`;
},
},
methods: {
changeLevelupSuppress () {
// @TODO: dispatch set({"preferences.suppressModals.levelUp":
// user.preferences.suppressModals.levelUp?true: false})
},
},
};
</script>

View file

@ -1,72 +1,177 @@
<template>
<small-modal
<b-modal
id="won-challenge"
:title="$t('wonChallenge')"
has-rewards
size="sm"
:hide-header="true"
>
<starred>
<div class="achievement-karaoke-2x"></div>
</starred>
<div class="text" v-html="$t('wonChallengeDesc', { challengeName })"></div>
<template #greyed>
<your-rewards />
<div class="w-100">
<div class="d-flex align-items-center justify-content-center">
<div
v-once
class="svg-icon gem mr-1"
v-html="icons.gem"
></div>
<strong>{{ challengePrize }}</strong>
</div>
<close-icon @click="close()" />
<div
class="text-center"
>
<h1
v-once
class="header purple"
>
{{ $t('wonChallenge') }}
</h1>
<div class="d-flex align-items-center justify-content-center mb-4">
<div
v-once
class="svg-icon sparkles sparkles-rotate"
v-html="icons.sparkles"
></div>
<div class="achievement-karaoke-2x"></div>
<div
v-once
class="svg-icon sparkles"
v-html="icons.sparkles"
></div>
</div>
</template>
</small-modal>
<p
class="mb-4 chal-desc"
v-html="$t('wonChallengeDesc', {challengeName: challengeName})"
>
</p>
</div>
<div
v-if="notification"
slot="modal-footer"
class="pt-3 w-100"
>
<div class="d-flex align-items-center justify-content-center mb-3">
<div
v-once
class="svg-icon stars"
v-html="icons.stars"
></div>
<strong v-once>{{ $t('yourReward') }}</strong>
<div
v-once
class="svg-icon stars stars-rotate"
v-html="icons.stars"
></div>
</div>
<div class="d-flex align-items-center justify-content-center mb-4">
<div
v-once
class="svg-icon gem mr-1"
v-html="icons.gem"
></div>
<strong>{{ notification.data.prize }}</strong>
</div>
<button
v-once
class="btn btn-primary"
@click="close()"
>
{{ $t('onwards') }}
</button>
</div>
</b-modal>
</template>
<style lang="scss">
@import '~@/assets/scss/colors.scss';
#won-challenge {
.modal-body {
padding: 0 1.5rem;
}
.modal-footer {
background: $gray-700;
border-top: none;
padding: 0 1.5rem 2rem 1.5rem;
}
.modal-dialog {
width: 20.625rem;
font-size: 0.875rem;
line-height: 1.71;
text-align: center;
}
}
</style>
<style lang="scss" scoped>
@import '~@/assets/scss/colors.scss';
.purple {
color: $purple-300;
}
.header {
font-size: 1.25rem;
line-height: 1.4;
text-align: center;
margin-top: 2rem;
}
.sparkles {
width: 2.5rem;
height: 4rem;
margin-left: 2rem;
&.sparkles-rotate {
transform: rotate(180deg);
margin-right: 2rem;
margin-left: 0rem;
}
}
.stars {
width: 2rem;
height: 1.063rem;
margin-right: 1.25rem;
&.stars-rotate {
transform: rotate(180deg);
margin-left: 1.25rem;
margin-right: 0rem;
}
}
.gem {
width: 1.5rem;
height: 1.5rem;
}
.text::v-deep p {
.chal-desc ::v-deep p {
display: inline;
}
</style>
<script>
import habiticaMarkdown from 'habitica-markdown';
import closeIcon from '@/components/shared/closeIcon';
import sparkles from '@/assets/svg/star-group.svg';
import gem from '@/assets/svg/gem.svg';
import smallModal from '@/components/ui/modal/smallModal';
import starred from '@/components/ui/modal/starred';
import yourRewards from '@/components/ui/modal/your-rewards';
import stars from '@/assets/svg/sparkles-left.svg';
import { mapState } from '@/libs/store';
export default {
components: {
smallModal,
starred,
yourRewards,
closeIcon,
},
data () {
// const tweet = this.$t('wonChallengeShare');
return {
// tweet,
notification: null,
icons: Object.freeze({ gem }),
icons: Object.freeze({
sparkles,
gem,
stars,
}),
};
},
computed: {
...mapState({ user: 'user.data' }),
challengeName () {
return this.notification
? habiticaMarkdown.render(String(this.notification.data.name)) : null;
},
challengePrize () {
return this.notification ? this.notification.data.prize : 0;
if (!this.notification) return null;
return habiticaMarkdown.render(String(this.notification.data.name));
},
},
mounted () {
@ -78,5 +183,10 @@ export default {
beforeDestroy () {
this.$root.$off('habitica:won-challenge');
},
methods: {
close () {
this.$root.$emit('bv::hide::modal', 'won-challenge');
},
},
};
</script>

View file

@ -1,12 +1,11 @@
<template>
<b-modal
id="payments-success-modal"
:title="$t('accountSuspendedTitle')"
:hide-footer="isFromBalance"
header-class="d-block justify-content-center pt-4 text-white"
footer-class="small-text justify-content-center p-3 greyed"
size="sm"
:modal-class="isFromBalance ? ['modal-hidden-footer'] : []"
>
<template #modal-header>
<div slot="modal-header">
<div class="check-container d-flex align-items-center justify-content-center">
<div
v-once
@ -14,106 +13,193 @@
v-html="icons.check"
></div>
</div>
<h2 class="text-center">{{ title }}</h2>
</template>
<section class="d-flex flex-column align-items-center text-center px-0">
<span v-html="subTitle" :class="{ 'font-weight-bold': boldSubTitle }"></span>
<div class="details-block d-flex text-center mt-3" :class="{ gems }" v-if="details">
<div
v-if="gems"
class="svg-icon mr-2"
v-html="icons.gem"
></div>
<span v-html="details"></span>
</div>
<span
v-if="renew"
class="small-text auto-renew mt-3"
>{{ $t('paymentAutoRenew') }}</span>
<button
<h2>{{ $t(isFromBalance ? 'success' : 'paymentSuccessful') }}</h2>
</div>
<div slot="modal-footer">
<div
v-once
class="btn btn-primary"
@click="close()"
class="small-text"
>
{{ $t('onwards') }}
</button>
</section>
<template #modal-footer>
{{ $t('giftSubscriptionText4') }}
</template>
{{ $t('giftSubscriptionText4') }}
</div>
</div>
<div class="row">
<div class="col-12 modal-body-col">
<template v-if="paymentData.paymentType === 'gems'">
<strong v-once>{{ $t('paymentYouReceived') }}</strong>
<div class="details-block gems">
<div
v-once
class="svg-icon"
v-html="icons.gem"
></div>
<span>{{ paymentData.gemsBlock.gems }}</span>
</div>
</template>
<template
v-if="paymentData.paymentType === 'gift-gems'
|| paymentData.paymentType === 'gift-gems-balance'"
>
<span v-html="$t('paymentYouSentGems', {name: paymentData.giftReceiver})"></span>
<div class="details-block gems">
<div
v-once
class="svg-icon"
v-html="icons.gem"
></div>
<span>{{ paymentData.gift.gems.amount }}</span>
</div>
</template>
<template v-if="paymentData.paymentType === 'gift-subscription'">
<span
v-html="$t('paymentYouSentSubscription', {
name: paymentData.giftReceiver, months: paymentData.subscription.months})"
></span>
</template>
<template v-if="paymentData.paymentType === 'subscription'">
<strong v-once>{{ $t('nowSubscribed') }}</strong>
<div class="details-block">
<span
v-html="$t('paymentSubBilling', {
amount: paymentData.subscription.price, months: paymentData.subscription.months})"
></span>
</div>
</template>
<template v-if="paymentData.paymentType === 'groupPlan'">
<span
v-html="$t(paymentData.newGroup
? 'groupPlanCreated' : 'groupPlanUpgraded', {groupName: paymentData.group.name})"
></span>
<div class="details-block">
<span
v-html="$t('paymentSubBilling', {
amount: groupPlanCost, months: paymentData.subscription.months})"
></span>
</div>
</template>
<template
v-if="paymentData.paymentType === 'groupPlan'
|| paymentData.paymentType === 'subscription'"
>
<span
v-once
class="small-text auto-renew"
>{{ $t('paymentAutoRenew') }}</span>
</template>
<button
v-once
class="btn btn-primary"
@click="close()"
>
{{ $t('onwards') }}
</button>
</div>
</div>
</b-modal>
</template>
<style lang="scss">
@import '~@/assets/scss/mixins.scss';
@import '~@/assets/scss/colors.scss';
#payments-success-modal .modal-dialog {
@include smallModal();
#payments-success-modal .modal-md {
max-width: 20.5rem;
}
#payments-success-modal .modal-content {
background: transparent;
}
#payments-success-modal.modal-hidden-footer .modal-body {
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px;
}
#payments-success-modal .modal-header {
justify-content: center;
padding-top: 24px;
padding-bottom: 0px;
background: $green-100;
border-top-right-radius: 8px;
border-top-left-radius: 8px;
border-bottom: none;
h2 {
color: white;
}
.check-container {
width: 64px;
height: 64px;
border-radius: 50%;
background: #1CA372;
margin: 0 auto;
margin-bottom: 16px;
}
.check {
width: 35.1px;
height: 28px;
color: white;
}
}
#payments-success-modal .modal-body {
padding-top: 16px;
padding-bottom: 24px;
background: white;
.modal-body-col {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
.btn.btn-primary {
margin-top: 24px;
}
}
.details-block {
background: $gray-700;
border-radius: 4px;
padding: 8px 24px;
margin-top: 16px;
display: flex;
flex-direction: row;
text-align: center;
&.gems {
padding: 12px 16px 12px 20px;
color: $green-10;
font-size: 24px;
font-weight: bold;
line-height: 1.33;
.svg-icon {
margin-right: 8px;
width: 32px;
height: 32px;
}
}
}
.auto-renew {
margin-top: 16px;
color: $orange-10;
font-style: normal;
}
}
#payments-success-modal .modal-footer {
background: $gray-700;
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px;
justify-content: center;
border-top: none;
.small-text {
font-style: normal;
}
.modal-header {
background: $green-100;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
h2 {
margin: 1rem;
color: inherit;
}
.check-container {
width: 4rem;
height: 4rem;
border-radius: 50%;
background: $green-10;
margin: 0 auto;
}
.check {
width: 35.1px;
height: 28px;
}
}
.modal-body {
padding: 1rem 1rem 0;
border-radius: 8px;
.details-block {
background: $gray-700;
border-radius: 4px;
padding: 0.5rem 1.5rem;
&.gems {
padding: 12px 16px 12px 20px;
color: $green-10;
font-size: 24px;
font-weight: bold;
line-height: 1.33;
.svg-icon {
width: 2rem;
height: 2rem;
}
}
}
.auto-renew {
color: $orange-10;
}
.btn.btn-primary {
margin: 1.5rem auto;
}
}
.modal-footer {
border-bottom-right-radius: 8px;
border-bottom-left-radius: 8px;
}
}
</style>
@ -122,10 +208,6 @@ import checkIcon from '@/assets/svg/check.svg';
import gemIcon from '@/assets/svg/gem.svg';
import subscriptionBlocks from '@/../../common/script/content/subscriptionBlocks';
function groupPlanCost (price, memberCount = 1) {
return price + 3 * (memberCount - 1);
}
export default {
data () {
return {
@ -133,66 +215,35 @@ export default {
check: checkIcon,
gem: gemIcon,
}),
isFromBalance: false,
gems: false,
boldSubTitle: false,
subTitle: '',
details: '',
renew: false,
paymentData: {},
};
},
computed: {
title () {
return this.$t(this.isFromBalance ? 'success' : 'paymentSuccessful');
groupPlanCost () {
const sub = this.paymentData.subscription;
const memberCount = this.paymentData.group.memberCount || 1;
return sub.price + 3 * (memberCount - 1);
},
isFromBalance () {
return this.paymentData.paymentType === 'gift-gems-balance';
},
},
mounted () {
this.$root.$on('habitica:payment-success', data => {
const type = data.paymentType;
this.isFromBalance = type.includes('balance');
this.gems = type.includes('gems');
if (this.gems) {
this.setGemData(type === 'gems', data);
} else {
this.setSubscriptionData(type, data);
if (['subscription', 'groupPlan', 'gift-subscription'].indexOf(data.paymentType) !== -1) {
data.subscription = subscriptionBlocks[data.subscriptionKey || data.gift.subscription.key];
}
this.paymentData = data;
this.$root.$emit('bv::show::modal', 'payments-success-modal');
});
},
beforeDestroy () {
this.paymentData = {};
this.$root.$off('habitica:payments-success');
},
methods: {
setGemData (boughtGems, data) {
this.subTitle = boughtGems ? this.$t('paymentYouReceived')
: this.$t('paymentYouSentGems', { name: data.giftReceiver });
this.boldSubTitle = boughtGems;
this.details = boughtGems ? data.gemsBlock.gems : data.gift.gems.amount;
this.renew = false;
},
setSubscriptionData (type, data) {
const { price, months } = subscriptionBlocks[
data.subscriptionKey || data.gift.subscription.key
];
const gift = type.includes('gift');
const groupPlan = type.includes('group');
const subbed = type === 'subscription';
const amount = groupPlan ? groupPlanCost(price, data.group.memberCount) : price;
if (groupPlan) {
this.subTitle = this.$t(data.newGroup ? 'groupPlanCreated'
: 'groupPlanUpgraded', { groupName: data.group.name });
} else {
this.subTitle = subbed ? this.$t('nowSubscribed')
: this.$t('paymentYouSentSubscription', { name: data.giftReceiver, months });
}
this.boldSubTitle = subbed;
this.details = gift ? '' : this.$t('paymentSubBilling', { amount, months });
this.renew = !gift;
},
close () {
this.paymentData = {};
this.$root.$emit('bv::hide::modal', 'payments-success-modal');
},
},

View file

@ -1,56 +0,0 @@
<template>
<b-modal
:id="id"
size="sm"
:title="title"
ok-only
:ok-title="$t(buttonTextKey)"
@ok="$emit('buttonClicked')"
:footer-class="{ greyed: isGreyedSlotPresent}"
:hide-footer="hideFooter"
:static="disableLazyRender"
>
<slot></slot>
<footer class="greyed" v-if="isGreyedSlotPresent && !hideFooter">
<slot name="greyed"></slot>
</footer>
</b-modal>
</template>
<style lang="scss">
@import '~@/assets/scss/mixins.scss';
.modal-dialog.modal-sm {
@include smallModal();
}
</style>
<script>
export default {
props: {
id: {
type: String,
required: true,
},
title: {
type: String,
required: true,
},
buttonTextKey: {
type: String,
default: 'onwards',
},
hideFooter: Boolean,
},
data () {
return { disableLazyRender: false };
},
computed: {
isGreyedSlotPresent () {
return Boolean(this.$slots.greyed);
},
},
};
</script>

View file

@ -1,40 +0,0 @@
<template>
<section class="d-flex">
<span
class="star-group mirror"
v-html="icons.starGroup"
></span>
<slot></slot>
<span
class="star-group"
v-html="icons.starGroup"
></span>
</section>
</template>
<style lang="scss">
.mirror {
transform: scaleX(-1);
}
.star-group {
margin: auto;
svg {
height: 4rem;
width: 2.5rem;
}
}
</style>
<script>
import starGroup from '@/assets/svg/star-group.svg';
export default {
data () {
return {
icons: Object.freeze({ starGroup }),
};
},
};
</script>

View file

@ -1,51 +0,0 @@
<template>
<div v-once class="your-rewards d-flex">
<span
class="sparkles"
v-html="icons.sparkles"
></span>
<span class="text">{{ $t('yourRewards') }}</span>
<span
class="sparkles mirror"
v-html="icons.sparkles"
></span>
</div>
</template>
<style lang="scss" scoped>
@import '~@/assets/scss/colors.scss';
.mirror {
transform: scaleX(-1);
}
.your-rewards {
min-height: 0;
margin: 0 auto;
width: fit-content;
.sparkles {
width: 2rem;
margin-top: .75rem;
}
.text {
min-height: 0;
font-weight: bold;
margin: 1rem;
color: $gray-50;
}
}
</style>
<script>
import sparkles from '@/assets/svg/sparkles-left.svg';
export default {
data () {
return {
icons: Object.freeze({ sparkles }),
};
},
};
</script>

View file

@ -1,61 +1,78 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Store from '@/libs/store';
import LevelUp from '@/components/achievements/levelUp.vue';
import LevelUp from '@/components/achievements/levelUp';
/*
// I couldn't get rendering to work for the modal, this is what I tried.
// Now the testing is done by overriding `this` for the exported computed
// functions directly. I intend to come back to this later to test it
// properly in a rendered component.
import { mount, createLocalVue } from '@vue/test-utils';
import BootstrapVue from 'bootstrap-vue';
import Store from '@/libs/store';
const localVue = createLocalVue();
localVue.use(Store);
localVue.use(BootstrapVue);
function createContainer () {
const container = document.createElement('div');
document.body.appendChild(container);
return container;
}
*/
describe('LevelUp', () => {
function createWrapper (level = 10) {
const wrapper = shallowMount(LevelUp, {
store: new Store({
state: {
user: {
data: {
stats: {
lvl: level,
buffs: {},
},
preferences: { hair: {} },
items: { gear: { equipped: {} } },
},
},
},
getters: { 'members:hasClass': () => () => false },
actions: {},
}),
localVue,
mocks: { $t: (...args) => args.map(JSON.stringify).join(' ') },
stubs: ['b-modal'],
function testFunction (name, level = 10) {
return LevelUp.computed[name].bind({
user: { stats: { lvl: level } },
$t: (...args) => args.map(JSON.stringify).join(' '),
});
return wrapper;
}
it('displays the right level in the title', () => {
const wrapper = createWrapper(12);
/*
// More potential rendering code
let wrapper;
beforeEach(async () => {
wrapper = mount(LevelUp, {
store: new Store({
state: { user: { data: createUser() } },
getters: {},
actions: {},
}),
propsData: {
static: true,
visible: true,
},
localVue,
mocks: { $t: string => string },
attachTo: createContainer(),
});
});
*/
expect(wrapper.vm.title).to.equal('"reachedLevel" {"level":12}');
it('displays the right level in the title', () => {
const title = testFunction('title', 12);
expect(title()).to.equal('"reachedLevel" {"level":12}');
});
it('does not display rewards for level 10', () => {
const wrapper = createWrapper();
const displayRewardQuest = testFunction('displayRewardQuest', 10);
expect(wrapper.vm.displayRewardQuest).to.be.false;
expect(displayRewardQuest()).to.be.false;
});
[15, 30, 40, 60].forEach(level => {
it(`does display rewards for level ${level}`, () => {
const wrapper = createWrapper(level);
const displayRewardQuest = testFunction('displayRewardQuest', level);
expect(wrapper.vm.displayRewardQuest).to.be.true;
expect(displayRewardQuest()).to.be.true;
});
});
it('generates the right test class for level 15', () => {
const wrapper = createWrapper(15);
const questClass = testFunction('questClass', 15);
expect(wrapper.vm.questClass).to.equal('scroll inventory_quest_scroll_atom1');
expect(questClass()).to.equal('scroll inventory_quest_scroll_atom1');
});
});

View file

@ -1,141 +0,0 @@
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Store from '@/libs/store';
import successModal from '@/components/payments/successModal';
const localVue = createLocalVue();
localVue.use(Store);
describe('Success modal', () => {
let wrapper;
function firePaymentSuccess (data) {
wrapper.vm.$root.$emit('habitica:payment-success', data);
}
beforeEach(async () => {
wrapper = shallowMount(successModal, {
store: new Store({
state: {},
getters: {},
actions: {},
}),
localVue,
mocks: { $t: (...args) => JSON.stringify(args) },
stubs: {
'b-modal': {
template: '<div><slot name="modal-header"></slot><slot></slot><footer><slot name="modal-footer"></slot></footer></div>',
},
},
});
});
it('Displays payment success when buying gems', () => {
firePaymentSuccess({
paymentType: 'gems',
gemsBlock: { gems: 5 },
});
expect(wrapper.find('h2').text()).to.equal('["paymentSuccessful"]');
expect(wrapper.find('section :first-child').text()).to.equal('["paymentYouReceived"]');
expect(wrapper.find('.details-block').text()).to.equal('5');
expect(wrapper.find('footer').text()).to.equal('["giftSubscriptionText4"]');
});
it('Displays success when gifting gems from balance', () => {
firePaymentSuccess({
paymentType: 'gift-gems-balance',
giftReceiver: 'Lucky User',
gift: { gems: { amount: 3 } },
});
expect(wrapper.find('h2').text()).to.equal('["success"]');
expect(wrapper.find('section :first-child').text()).to.equal('["paymentYouSentGems",{"name":"Lucky User"}]');
expect(wrapper.find('.details-block').text()).to.equal('3');
});
it('Displays payment success when gifting gems through payment', () => {
firePaymentSuccess({
paymentType: 'gift-gems',
giftReceiver: 'Lucky User',
gift: { gems: { amount: 7 } },
});
expect(wrapper.find('h2').text()).to.equal('["paymentSuccessful"]');
expect(wrapper.find('section :first-child').text()).to.equal('["paymentYouSentGems",{"name":"Lucky User"}]');
expect(wrapper.find('.details-block').text()).to.equal('7');
expect(wrapper.find('footer').text()).to.equal('["giftSubscriptionText4"]');
});
it('Displays payment success when gifting subscription', () => {
firePaymentSuccess({
paymentType: 'gift-subscription',
giftReceiver: 'Very lucky User',
subscriptionKey: 'basic_6mo',
});
expect(wrapper.find('h2').text()).to.equal('["paymentSuccessful"]');
expect(wrapper.find('section :first-child').text()).to.equal('["paymentYouSentSubscription",{"name":"Very lucky User","months":6}]');
expect(wrapper.find('.details-block').exists()).to.be.false;
expect(wrapper.find('footer').text()).to.equal('["giftSubscriptionText4"]');
});
it('Displays payment success when subscribing', () => {
firePaymentSuccess({
paymentType: 'subscription',
subscriptionKey: 'basic_6mo',
});
expect(wrapper.find('h2').text()).to.equal('["paymentSuccessful"]');
expect(wrapper.find('section :first-child').text()).to.equal('["nowSubscribed"]');
expect(wrapper.find('.details-block').text()).to.equal('["paymentSubBilling",{"amount":30,"months":6}]');
expect(wrapper.find('footer').text()).to.equal('["giftSubscriptionText4"]');
});
it('Displays payment success when creating new group plan', () => {
firePaymentSuccess({
paymentType: 'groupPlan',
subscriptionKey: 'basic_6mo',
newGroup: true,
group: {
name: 'The best group',
memberCount: 5,
},
});
expect(wrapper.find('h2').text()).to.equal('["paymentSuccessful"]');
expect(wrapper.find('section :first-child').text()).to.equal('["groupPlanCreated",{"groupName":"The best group"}]');
expect(wrapper.find('.details-block').text()).to.equal('["paymentSubBilling",{"amount":42,"months":6}]');
expect(wrapper.find('footer').text()).to.equal('["giftSubscriptionText4"]');
});
it('Displays payment success when upgrading group plan', () => {
firePaymentSuccess({
paymentType: 'groupPlan',
subscriptionKey: 'basic_6mo',
group: {
name: 'The best group',
memberCount: 2,
},
});
expect(wrapper.find('h2').text()).to.equal('["paymentSuccessful"]');
expect(wrapper.find('section :first-child').text()).to.equal('["groupPlanUpgraded",{"groupName":"The best group"}]');
expect(wrapper.find('.details-block').text()).to.equal('["paymentSubBilling",{"amount":33,"months":6}]');
expect(wrapper.find('footer').text()).to.equal('["giftSubscriptionText4"]');
});
it('Displays payment success when upgrading group plan without memberCount', () => {
firePaymentSuccess({
paymentType: 'groupPlan',
subscriptionKey: 'basic_3mo',
group: { name: 'The solo group' },
});
expect(wrapper.find('h2').text()).to.equal('["paymentSuccessful"]');
expect(wrapper.find('section :first-child').text()).to.equal('["groupPlanUpgraded",{"groupName":"The solo group"}]');
expect(wrapper.find('.details-block').text()).to.equal('["paymentSubBilling",{"amount":15,"months":3}]');
expect(wrapper.find('footer').text()).to.equal('["giftSubscriptionText4"]');
});
});

View file

@ -1,33 +0,0 @@
import { mount, createLocalVue } from '@vue/test-utils';
import BootstrapVue from 'bootstrap-vue';
import Store from '@/libs/store';
import smallModal from '@/components/ui/modal/smallModal';
const localVue = createLocalVue();
localVue.use(Store);
localVue.use(BootstrapVue);
describe('Small modal', () => {
let wrapper;
beforeEach(async () => {
wrapper = mount(smallModal, {
store: new Store({
state: {},
getters: {},
actions: {},
}),
propsData: {
id: 'test-small-modal',
title: 'Test title',
},
localVue,
mocks: { $t: (s, args) => s + JSON.stringify(args) },
});
wrapper.setData({ disableLazyRender: true });
});
it('Displays passed in title in Bootstrap modal with passed in ID', () => {
expect(wrapper.find('#test-small-modal .modal-sm .modal-title').text()).to.equal('Test title');
});
});