Compare commits
84 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87b9e72b56 | ||
|
|
962662fe7c | ||
|
|
349a1032b6 | ||
|
|
476131835d | ||
|
|
8237b7f2de | ||
|
|
6ee2b3690a | ||
|
|
a08cca807a | ||
|
|
8c51f36784 | ||
|
|
d35f81cdae | ||
|
|
1d1b25391f | ||
|
|
ec81c02d72 | ||
|
|
166da3c2f8 | ||
|
|
23b72a673d | ||
|
|
d22b4bb2f7 | ||
|
|
aaebd4da77 | ||
|
|
b128e7874e | ||
|
|
1e10e20a24 | ||
|
|
b1aeb8ed87 | ||
|
|
2cb80e2275 | ||
|
|
ee32e24ff2 | ||
|
|
af40c437be | ||
|
|
a99150c485 | ||
|
|
696b67204d | ||
|
|
4f3536e887 | ||
|
|
07e5bf1437 | ||
|
|
d2ca738256 | ||
|
|
f7983f39eb | ||
|
|
7c954f7073 | ||
|
|
82d0e737a6 | ||
|
|
f8213aaf1b | ||
|
|
2335ad4167 | ||
|
|
d84631255b | ||
|
|
0b352b9103 | ||
|
|
19b75c6257 | ||
|
|
b66904a3a7 | ||
|
|
cfbfec34aa | ||
|
|
88f28188a1 | ||
|
|
fce5be2e8f | ||
|
|
1d68cbfaa2 | ||
|
|
a44222a350 | ||
|
|
4d2510e322 | ||
|
|
3b5ed33e03 | ||
|
|
0a6bf92b6b | ||
|
|
05ae40bc2e | ||
|
|
57e96ea092 | ||
|
|
ea49b5b8e0 | ||
|
|
11a5de714a | ||
|
|
f74b4d3e73 | ||
|
|
ab6fdb99af | ||
|
|
e3efa557dd | ||
|
|
a6cea47789 | ||
|
|
5a200a88bd | ||
|
|
545499ea0b | ||
|
|
3e7f4229ec | ||
|
|
56d5f77b6e | ||
|
|
efdf5a2e16 | ||
|
|
add3a2887f | ||
|
|
0ed7c7596a | ||
|
|
55a452694f | ||
|
|
cd4d5f83ff | ||
|
|
8220199e49 | ||
|
|
bd1f6918ba | ||
|
|
5b21e62647 | ||
|
|
5e76d6df21 | ||
|
|
7348145b7d | ||
|
|
ba2832d21f | ||
|
|
688f5084a1 | ||
|
|
d5955b8889 | ||
|
|
01fd17ee3f | ||
|
|
979497dd35 | ||
|
|
a2c8b8b05c | ||
|
|
8750701c08 | ||
|
|
8441b0a3d6 | ||
|
|
0667695390 | ||
|
|
4d322c1bf6 | ||
|
|
a855ddacc7 | ||
|
|
9d48ef7322 | ||
|
|
95f3315796 | ||
|
|
5e232d8c9f | ||
|
|
13793f8b3c | ||
|
|
55f875f95a | ||
|
|
14576be374 | ||
|
|
4cb2c26475 | ||
|
|
3d757c7814 |
@@ -8,6 +8,7 @@ ENV BASE_URL https://habitica.com
|
||||
ENV FACEBOOK_KEY 128307497299777
|
||||
ENV GA_ID UA-33510635-1
|
||||
ENV GOOGLE_CLIENT_ID 1035232791481-32vtplgnjnd1aufv3mcu1lthf31795fq.apps.googleusercontent.com
|
||||
ENV LOGGLY_CLIENT_TOKEN ab5663bf-241f-4d14-8783-7d80db77089a
|
||||
ENV NODE_ENV production
|
||||
ENV STRIPE_PUB_KEY pk_85fQ0yMECHNfHTSsZoxZXlPSwSNfA
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ gulp.task('test:content:safe', gulp.series('test:prepare:build', (cb) => {
|
||||
|
||||
gulp.task('test:api:unit', (done) => {
|
||||
let runner = exec(
|
||||
testBin('node_modules/.bin/istanbul cover --dir coverage/api-unit node_modules/mocha/bin/_mocha -- test/api/unit --recursive --require ./test/helpers/start-server'),
|
||||
testBin('istanbul cover --dir coverage/api-unit node_modules/mocha/bin/_mocha -- test/api/unit --recursive --require ./test/helpers/start-server'),
|
||||
(err) => {
|
||||
if (err) {
|
||||
process.exit(1);
|
||||
@@ -180,12 +180,12 @@ gulp.task('test:api:unit', (done) => {
|
||||
});
|
||||
|
||||
gulp.task('test:api:unit:watch', () => {
|
||||
return gulp.watch(['website/server/libs/*', 'test/api/v3/unit/**/*', 'website/server/controllers/**/*'], gulp.series('test:api:unit', done => done()));
|
||||
return gulp.watch(['website/server/libs/*', 'test/api/unit/**/*', 'website/server/controllers/**/*'], gulp.series('test:api:unit', done => done()));
|
||||
});
|
||||
|
||||
gulp.task('test:api-v3:integration', (done) => {
|
||||
let runner = exec(
|
||||
testBin('node_modules/.bin/istanbul cover --dir coverage/api-v3-integration --report lcovonly node_modules/mocha/bin/_mocha -- test/api/v3/integration --recursive --require ./test/helpers/start-server'),
|
||||
testBin('istanbul cover --dir coverage/api-v3-integration --report lcovonly node_modules/mocha/bin/_mocha -- test/api/v3/integration --recursive --require ./test/helpers/start-server'),
|
||||
{maxBuffer: 500 * 1024},
|
||||
(err) => {
|
||||
if (err) {
|
||||
@@ -217,7 +217,7 @@ gulp.task('test:api-v3:integration:separate-server', (done) => {
|
||||
|
||||
gulp.task('test:api-v4:integration', (done) => {
|
||||
let runner = exec(
|
||||
testBin('node_modules/.bin/istanbul cover --dir coverage/api-v4-integration --report lcovonly node_modules/mocha/bin/_mocha -- test/api/v4 --recursive --require ./test/helpers/start-server'),
|
||||
testBin('istanbul cover --dir coverage/api-v4-integration --report lcovonly node_modules/mocha/bin/_mocha -- test/api/v4 --recursive --require ./test/helpers/start-server'),
|
||||
{maxBuffer: 500 * 1024},
|
||||
(err) => {
|
||||
if (err) {
|
||||
@@ -254,4 +254,4 @@ gulp.task('test:api-v3', gulp.series(
|
||||
'test:api:unit',
|
||||
'test:api-v3:integration',
|
||||
done => done()
|
||||
));
|
||||
));
|
||||
|
||||
110
migrations/archive/2018/20181231_nye.js
Normal file
@@ -0,0 +1,110 @@
|
||||
/* eslint-disable no-console */
|
||||
const MIGRATION_NAME = '20181231_nye';
|
||||
import { model as User } from '../../../website/server/models/user';
|
||||
import mongoose from 'mongoose';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
async function updateUser (user) {
|
||||
count++;
|
||||
|
||||
const set = {'flags.newStuff': true};
|
||||
let push;
|
||||
|
||||
set.migration = MIGRATION_NAME;
|
||||
|
||||
if (typeof user.items.gear.owned.head_special_nye2017 !== 'undefined') {
|
||||
set['items.gear.owned.head_special_nye2018'] = false;
|
||||
push = [
|
||||
{
|
||||
type: 'marketGear',
|
||||
path: 'gear.flat.head_special_nye2018',
|
||||
_id: uuid(),
|
||||
},
|
||||
];
|
||||
} else if (typeof user.items.gear.owned.head_special_nye2016 !== 'undefined') {
|
||||
set['items.gear.owned.head_special_nye2017'] = false;
|
||||
push = [
|
||||
{
|
||||
type: 'marketGear',
|
||||
path: 'gear.flat.head_special_nye2017',
|
||||
_id: uuid(),
|
||||
},
|
||||
];
|
||||
} else if (typeof user.items.gear.owned.head_special_nye2015 !== 'undefined') {
|
||||
set['items.gear.owned.head_special_nye2016'] = false;
|
||||
push = [
|
||||
{
|
||||
type: 'marketGear',
|
||||
path: 'gear.flat.head_special_nye2016',
|
||||
_id: uuid(),
|
||||
},
|
||||
];
|
||||
} else if (typeof user.items.gear.owned.head_special_nye2014 !== 'undefined') {
|
||||
set['items.gear.owned.head_special_nye2015'] = false;
|
||||
push = [
|
||||
{
|
||||
type: 'marketGear',
|
||||
path: 'gear.flat.head_special_nye2015',
|
||||
_id: uuid(),
|
||||
},
|
||||
];
|
||||
} else if (typeof user.items.gear.owned.head_special_nye !== 'undefined') {
|
||||
set['items.gear.owned.head_special_nye2014'] = false;
|
||||
push = [
|
||||
{
|
||||
type: 'marketGear',
|
||||
path: 'gear.flat.head_special_nye2014',
|
||||
_id: uuid(),
|
||||
},
|
||||
];
|
||||
} else {
|
||||
set['items.gear.owned.head_special_nye'] = false;
|
||||
push = [
|
||||
{
|
||||
type: 'marketGear',
|
||||
path: 'gear.flat.head_special_nye',
|
||||
_id: uuid(),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
|
||||
return await User.update({_id: user._id}, {$set: set, $push: {pinnedItems: {$each: push}}}).exec();
|
||||
}
|
||||
|
||||
module.exports = async function processUsers () {
|
||||
let query = {
|
||||
migration: {$ne: MIGRATION_NAME},
|
||||
};
|
||||
|
||||
const fields = {
|
||||
_id: 1,
|
||||
items: 1,
|
||||
};
|
||||
|
||||
while (true) { // eslint-disable-line no-constant-condition
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({_id: 1})
|
||||
.select(fields)
|
||||
.lean()
|
||||
.exec();
|
||||
|
||||
if (users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
break;
|
||||
} else {
|
||||
query._id = {
|
||||
$gt: users[users.length - 1],
|
||||
};
|
||||
}
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
};
|
||||
@@ -17,7 +17,7 @@ function setUpServer () {
|
||||
setUpServer();
|
||||
|
||||
// Replace this with your migration
|
||||
const processUsers = require('./users/20181122_turkey_day.js');
|
||||
const processUsers = require('./archive/2018/20181231_nye.js');
|
||||
processUsers()
|
||||
.then(function success () {
|
||||
process.exit(0);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable no-console */
|
||||
const MIGRATION_NAME = 'mystery_items_201811';
|
||||
const MYSTERY_ITEMS = ['head_mystery_201811', 'weapon_mystery_201811'];
|
||||
const MIGRATION_NAME = 'mystery_items_201812';
|
||||
const MYSTERY_ITEMS = ['headAccessory_mystery_201812', 'back_mystery_201812'];
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
import { model as UserNotification } from '../../website/server/models/userNotification';
|
||||
|
||||
|
||||
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"version": "4.75.4",
|
||||
"version": "4.80.2",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
|
||||
"version": "4.75.4",
|
||||
"version": "4.80.2",
|
||||
"main": "./website/server/index.js",
|
||||
"dependencies": {
|
||||
"@slack/client": "^3.8.1",
|
||||
|
||||
@@ -27,12 +27,13 @@ async function _deleteAmplitudeData (userId, email) {
|
||||
if (response) console.log(`${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
async function _deleteHabiticaData (user) {
|
||||
async function _deleteHabiticaData (user, email) {
|
||||
await User.update(
|
||||
{_id: user._id},
|
||||
{$set: {
|
||||
'auth.local.passwordHashMethod': 'bcrypt',
|
||||
'auth.local.email': email,
|
||||
'auth.local.hashed_password': '$2a$10$QDnNh1j1yMPnTXDEOV38xOePEWFd4X8DSYwAM8XTmqmacG5X0DKjW',
|
||||
'auth.local.passwordHashMethod': 'bcrypt',
|
||||
}}
|
||||
);
|
||||
const response = await axios.delete(
|
||||
@@ -75,7 +76,7 @@ async function _processEmailAddress (email) {
|
||||
} else {
|
||||
for (const user of users) {
|
||||
await _deleteAmplitudeData(user._id, email); // eslint-disable-line no-await-in-loop
|
||||
await _deleteHabiticaData(user); // eslint-disable-line no-await-in-loop
|
||||
await _deleteHabiticaData(user, email); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import iap from '../../../../../website/server/libs/inAppPurchases';
|
||||
import {model as User} from '../../../../../website/server/models/user';
|
||||
import common from '../../../../../website/common';
|
||||
import moment from 'moment';
|
||||
import {mockFindById, restoreFindById} from '../../../../helpers/mongoose.helper';
|
||||
|
||||
const i18n = common.i18n;
|
||||
|
||||
@@ -49,7 +50,7 @@ describe('Apple Payments', () => {
|
||||
iapIsValidatedStub = sinon.stub(iapModule, 'isValidated')
|
||||
.returns(false);
|
||||
|
||||
await expect(applePayments.verifyGemPurchase(user, receipt, headers))
|
||||
await expect(applePayments.verifyGemPurchase({user, receipt, headers}))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
@@ -61,7 +62,7 @@ describe('Apple Payments', () => {
|
||||
iapGetPurchaseDataStub.restore();
|
||||
iapGetPurchaseDataStub = sinon.stub(iapModule, 'getPurchaseData').returns([]);
|
||||
|
||||
await expect(applePayments.verifyGemPurchase(user, receipt, headers))
|
||||
await expect(applePayments.verifyGemPurchase({user, receipt, headers}))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
@@ -71,7 +72,7 @@ describe('Apple Payments', () => {
|
||||
|
||||
it('errors if the user cannot purchase gems', async () => {
|
||||
sinon.stub(user, 'canGetGems').resolves(false);
|
||||
await expect(applePayments.verifyGemPurchase(user, receipt, headers))
|
||||
await expect(applePayments.verifyGemPurchase({user, receipt, headers}))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
@@ -89,7 +90,7 @@ describe('Apple Payments', () => {
|
||||
transactionId: token,
|
||||
}]);
|
||||
|
||||
await expect(applePayments.verifyGemPurchase(user, receipt, headers))
|
||||
await expect(applePayments.verifyGemPurchase({user, receipt, headers}))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
@@ -131,7 +132,7 @@ describe('Apple Payments', () => {
|
||||
}]);
|
||||
|
||||
sinon.stub(user, 'canGetGems').resolves(true);
|
||||
await applePayments.verifyGemPurchase(user, receipt, headers);
|
||||
await applePayments.verifyGemPurchase({user, receipt, headers});
|
||||
|
||||
expect(iapSetupStub).to.be.calledOnce;
|
||||
expect(iapValidateStub).to.be.calledOnce;
|
||||
@@ -151,6 +152,38 @@ describe('Apple Payments', () => {
|
||||
user.canGetGems.restore();
|
||||
});
|
||||
});
|
||||
|
||||
it('gifts gems', async () => {
|
||||
const receivingUser = new User();
|
||||
await receivingUser.save();
|
||||
|
||||
mockFindById(receivingUser);
|
||||
|
||||
iapGetPurchaseDataStub.restore();
|
||||
iapGetPurchaseDataStub = sinon.stub(iapModule, 'getPurchaseData')
|
||||
.returns([{productId: gemsCanPurchase[0].productId,
|
||||
transactionId: token,
|
||||
}]);
|
||||
|
||||
const gift = {uuid: receivingUser._id};
|
||||
await applePayments.verifyGemPurchase({user, gift, receipt, headers});
|
||||
|
||||
expect(iapSetupStub).to.be.calledOnce;
|
||||
expect(iapValidateStub).to.be.calledOnce;
|
||||
expect(iapValidateStub).to.be.calledWith(iap.APPLE, receipt);
|
||||
expect(iapIsValidatedStub).to.be.calledOnce;
|
||||
expect(iapIsValidatedStub).to.be.calledWith({});
|
||||
expect(iapGetPurchaseDataStub).to.be.calledOnce;
|
||||
|
||||
expect(paymentBuyGemsStub).to.be.calledOnce;
|
||||
expect(paymentBuyGemsStub).to.be.calledWith({
|
||||
user: receivingUser,
|
||||
paymentMethod: applePayments.constants.PAYMENT_METHOD_APPLE,
|
||||
amount: gemsCanPurchase[0].amount,
|
||||
headers,
|
||||
});
|
||||
restoreFindById();
|
||||
});
|
||||
});
|
||||
|
||||
describe('subscribe', () => {
|
||||
|
||||
@@ -6,6 +6,7 @@ import iap from '../../../../../website/server/libs/inAppPurchases';
|
||||
import {model as User} from '../../../../../website/server/models/user';
|
||||
import common from '../../../../../website/common';
|
||||
import moment from 'moment';
|
||||
import {mockFindById, restoreFindById} from '../../../../helpers/mongoose.helper';
|
||||
|
||||
const i18n = common.i18n;
|
||||
|
||||
@@ -44,7 +45,7 @@ describe('Google Payments', () => {
|
||||
iapIsValidatedStub = sinon.stub(iapModule, 'isValidated')
|
||||
.returns(false);
|
||||
|
||||
await expect(googlePayments.verifyGemPurchase(user, receipt, signature, headers))
|
||||
await expect(googlePayments.verifyGemPurchase({user, receipt, signature, headers}))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
@@ -55,7 +56,7 @@ describe('Google Payments', () => {
|
||||
it('should throw an error if productId is invalid', async () => {
|
||||
receipt = `{"token": "${token}", "productId": "invalid"}`;
|
||||
|
||||
await expect(googlePayments.verifyGemPurchase(user, receipt, signature, headers))
|
||||
await expect(googlePayments.verifyGemPurchase({user, receipt, signature, headers}))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
@@ -66,7 +67,7 @@ describe('Google Payments', () => {
|
||||
it('should throw an error if user cannot purchase gems', async () => {
|
||||
sinon.stub(user, 'canGetGems').resolves(false);
|
||||
|
||||
await expect(googlePayments.verifyGemPurchase(user, receipt, signature, headers))
|
||||
await expect(googlePayments.verifyGemPurchase({user, receipt, signature, headers}))
|
||||
.to.eventually.be.rejected.and.to.eql({
|
||||
httpCode: 401,
|
||||
name: 'NotAuthorized',
|
||||
@@ -78,7 +79,7 @@ describe('Google Payments', () => {
|
||||
|
||||
it('purchases gems', async () => {
|
||||
sinon.stub(user, 'canGetGems').resolves(true);
|
||||
await googlePayments.verifyGemPurchase(user, receipt, signature, headers);
|
||||
await googlePayments.verifyGemPurchase({user, receipt, signature, headers});
|
||||
|
||||
expect(iapSetupStub).to.be.calledOnce;
|
||||
expect(iapValidateStub).to.be.calledOnce;
|
||||
@@ -99,6 +100,34 @@ describe('Google Payments', () => {
|
||||
expect(user.canGetGems).to.be.calledOnce;
|
||||
user.canGetGems.restore();
|
||||
});
|
||||
|
||||
it('gifts gems', async () => {
|
||||
const receivingUser = new User();
|
||||
await receivingUser.save();
|
||||
|
||||
mockFindById(receivingUser);
|
||||
|
||||
const gift = {uuid: receivingUser._id};
|
||||
await googlePayments.verifyGemPurchase({user, gift, receipt, signature, headers});
|
||||
|
||||
expect(iapSetupStub).to.be.calledOnce;
|
||||
expect(iapValidateStub).to.be.calledOnce;
|
||||
expect(iapValidateStub).to.be.calledWith(iap.GOOGLE, {
|
||||
data: receipt,
|
||||
signature,
|
||||
});
|
||||
expect(iapIsValidatedStub).to.be.calledOnce;
|
||||
expect(iapIsValidatedStub).to.be.calledWith({});
|
||||
|
||||
expect(paymentBuyGemsStub).to.be.calledOnce;
|
||||
expect(paymentBuyGemsStub).to.be.calledWith({
|
||||
user: receivingUser,
|
||||
paymentMethod: googlePayments.constants.PAYMENT_METHOD_GOOGLE,
|
||||
amount: 5.25,
|
||||
headers,
|
||||
});
|
||||
restoreFindById();
|
||||
});
|
||||
});
|
||||
|
||||
describe('subscribe', () => {
|
||||
|
||||
@@ -209,7 +209,7 @@ describe('payments/index', () => {
|
||||
await api.createSubscription(data);
|
||||
let msg = '\`Hello recipient, sender has sent you 3 months of subscription!\`';
|
||||
|
||||
expect(user.sendMessage).to.be.calledOnce;
|
||||
expect(user.sendMessage).to.be.calledTwice;
|
||||
expect(user.sendMessage).to.be.calledWith(recipient, { receiverMsg: msg, senderMsg: msg, save: false });
|
||||
});
|
||||
|
||||
@@ -247,6 +247,77 @@ describe('payments/index', () => {
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
context('Winter 2018-19 Gift-1-Get-1 Promotion', async () => {
|
||||
it('creates a gift subscription for purchaser and recipient if none exist', async () => {
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.items.pets['Jackalope-RoyalPurple']).to.eql(5);
|
||||
expect(user.purchased.plan.customerId).to.eql('Gift');
|
||||
expect(user.purchased.plan.dateTerminated).to.exist;
|
||||
expect(user.purchased.plan.dateUpdated).to.exist;
|
||||
expect(user.purchased.plan.dateCreated).to.exist;
|
||||
|
||||
expect(recipient.items.pets['Jackalope-RoyalPurple']).to.eql(5);
|
||||
expect(recipient.purchased.plan.customerId).to.eql('Gift');
|
||||
expect(recipient.purchased.plan.dateTerminated).to.exist;
|
||||
expect(recipient.purchased.plan.dateUpdated).to.exist;
|
||||
expect(recipient.purchased.plan.dateCreated).to.exist;
|
||||
});
|
||||
|
||||
it('adds extraMonths to existing subscription for purchaser and creates a gift subscription for recipient without sub', async () => {
|
||||
user.purchased.plan = plan;
|
||||
|
||||
expect(user.purchased.plan.extraMonths).to.eql(0);
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.extraMonths).to.eql(3);
|
||||
|
||||
expect(recipient.items.pets['Jackalope-RoyalPurple']).to.eql(5);
|
||||
expect(recipient.purchased.plan.customerId).to.eql('Gift');
|
||||
expect(recipient.purchased.plan.dateTerminated).to.exist;
|
||||
expect(recipient.purchased.plan.dateUpdated).to.exist;
|
||||
expect(recipient.purchased.plan.dateCreated).to.exist;
|
||||
});
|
||||
|
||||
it('adds extraMonths to existing subscription for recipient and creates a gift subscription for purchaser without sub', async () => {
|
||||
recipient.purchased.plan = plan;
|
||||
|
||||
expect(recipient.purchased.plan.extraMonths).to.eql(0);
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(recipient.purchased.plan.extraMonths).to.eql(3);
|
||||
|
||||
expect(user.items.pets['Jackalope-RoyalPurple']).to.eql(5);
|
||||
expect(user.purchased.plan.customerId).to.eql('Gift');
|
||||
expect(user.purchased.plan.dateTerminated).to.exist;
|
||||
expect(user.purchased.plan.dateUpdated).to.exist;
|
||||
expect(user.purchased.plan.dateCreated).to.exist;
|
||||
});
|
||||
|
||||
it('adds extraMonths to existing subscriptions for purchaser and recipient', async () => {
|
||||
user.purchased.plan = plan;
|
||||
recipient.purchased.plan = plan;
|
||||
|
||||
expect(user.purchased.plan.extraMonths).to.eql(0);
|
||||
expect(recipient.purchased.plan.extraMonths).to.eql(0);
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.extraMonths).to.eql(3);
|
||||
expect(recipient.purchased.plan.extraMonths).to.eql(3);
|
||||
});
|
||||
|
||||
it('sends a private message about the promotion', async () => {
|
||||
await api.createSubscription(data);
|
||||
let msg = '\`Hello sender, you received 3 months of subscription as part of our holiday gift-giving promotion!\`';
|
||||
|
||||
expect(user.sendMessage).to.be.calledTwice;
|
||||
expect(user.sendMessage).to.be.calledWith(user, { senderMsg: msg });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('Purchasing a subscription for self', () => {
|
||||
|
||||
@@ -32,8 +32,19 @@ describe('Group Model', () => {
|
||||
privacy: 'private',
|
||||
});
|
||||
|
||||
let _progress = {
|
||||
up: 10,
|
||||
down: 8,
|
||||
collectedItems: 5,
|
||||
};
|
||||
|
||||
questLeader = new User({
|
||||
party: { _id: party._id },
|
||||
party: {
|
||||
_id: party._id,
|
||||
quest: {
|
||||
progress: _progress,
|
||||
},
|
||||
},
|
||||
profile: { name: 'Quest Leader' },
|
||||
items: {
|
||||
quests: {
|
||||
@@ -45,20 +56,40 @@ describe('Group Model', () => {
|
||||
party.leader = questLeader._id;
|
||||
|
||||
participatingMember = new User({
|
||||
party: { _id: party._id },
|
||||
party: {
|
||||
_id: party._id,
|
||||
quest: {
|
||||
progress: _progress,
|
||||
},
|
||||
},
|
||||
profile: { name: 'Participating Member' },
|
||||
});
|
||||
sleepingParticipatingMember = new User({
|
||||
party: { _id: party._id },
|
||||
party: {
|
||||
_id: party._id,
|
||||
quest: {
|
||||
progress: _progress,
|
||||
},
|
||||
},
|
||||
profile: { name: 'Sleeping Participating Member' },
|
||||
preferences: { sleep: true },
|
||||
});
|
||||
nonParticipatingMember = new User({
|
||||
party: { _id: party._id },
|
||||
party: {
|
||||
_id: party._id,
|
||||
quest: {
|
||||
progress: _progress,
|
||||
},
|
||||
},
|
||||
profile: { name: 'Non-Participating Member' },
|
||||
});
|
||||
undecidedMember = new User({
|
||||
party: { _id: party._id },
|
||||
party: {
|
||||
_id: party._id,
|
||||
quest: {
|
||||
progress: _progress,
|
||||
},
|
||||
},
|
||||
profile: { name: 'Undecided Member' },
|
||||
});
|
||||
|
||||
@@ -1163,16 +1194,17 @@ describe('Group Model', () => {
|
||||
expect(party.quest.members).to.eql(expectedQuestMembers);
|
||||
});
|
||||
|
||||
it('applies updates to user object directly if user is participating', async () => {
|
||||
it('applies updates to user object directly if user is participating (without resetting progress, except progress.down)', async () => {
|
||||
await party.startQuest(participatingMember);
|
||||
|
||||
expect(participatingMember.party.quest.key).to.eql('whale');
|
||||
expect(participatingMember.party.quest.progress.up).to.eql(10);
|
||||
expect(participatingMember.party.quest.progress.down).to.eql(0);
|
||||
expect(participatingMember.party.quest.progress.collectedItems).to.eql(0);
|
||||
expect(participatingMember.party.quest.progress.collectedItems).to.eql(5);
|
||||
expect(participatingMember.party.quest.completed).to.eql(null);
|
||||
});
|
||||
|
||||
it('applies updates to other participating members', async () => {
|
||||
it('applies updates to other participating members (without resetting progress, except progress.down)', async () => {
|
||||
await party.startQuest(nonParticipatingMember);
|
||||
|
||||
questLeader = await User.findById(questLeader._id);
|
||||
@@ -1180,18 +1212,21 @@ describe('Group Model', () => {
|
||||
sleepingParticipatingMember = await User.findById(sleepingParticipatingMember._id);
|
||||
|
||||
expect(participatingMember.party.quest.key).to.eql('whale');
|
||||
expect(participatingMember.party.quest.progress.up).to.eql(10);
|
||||
expect(participatingMember.party.quest.progress.down).to.eql(0);
|
||||
expect(participatingMember.party.quest.progress.collectedItems).to.eql(0);
|
||||
expect(participatingMember.party.quest.progress.collectedItems).to.eql(5);
|
||||
expect(participatingMember.party.quest.completed).to.eql(null);
|
||||
|
||||
expect(sleepingParticipatingMember.party.quest.key).to.eql('whale');
|
||||
expect(sleepingParticipatingMember.party.quest.progress.up).to.eql(10);
|
||||
expect(sleepingParticipatingMember.party.quest.progress.down).to.eql(0);
|
||||
expect(sleepingParticipatingMember.party.quest.progress.collectedItems).to.eql(0);
|
||||
expect(sleepingParticipatingMember.party.quest.progress.collectedItems).to.eql(5);
|
||||
expect(sleepingParticipatingMember.party.quest.completed).to.eql(null);
|
||||
|
||||
expect(questLeader.party.quest.key).to.eql('whale');
|
||||
expect(questLeader.party.quest.progress.up).to.eql(10);
|
||||
expect(questLeader.party.quest.progress.down).to.eql(0);
|
||||
expect(questLeader.party.quest.progress.collectedItems).to.eql(0);
|
||||
expect(questLeader.party.quest.progress.collectedItems).to.eql(5);
|
||||
expect(questLeader.party.quest.completed).to.eql(null);
|
||||
});
|
||||
|
||||
@@ -1202,6 +1237,9 @@ describe('Group Model', () => {
|
||||
undecidedMember = await User.findById(undecidedMember._id);
|
||||
|
||||
expect(nonParticipatingMember.party.quest.key).to.not.eql('whale');
|
||||
expect(nonParticipatingMember.party.quest.progress.up).to.eql(10);
|
||||
expect(nonParticipatingMember.party.quest.progress.down).to.eql(8);
|
||||
expect(nonParticipatingMember.party.quest.progress.collectedItems).to.eql(5);
|
||||
expect(undecidedMember.party.quest.key).to.not.eql('whale');
|
||||
});
|
||||
|
||||
@@ -1369,8 +1407,9 @@ describe('Group Model', () => {
|
||||
let userQuest = participatingMember.party.quest;
|
||||
|
||||
expect(userQuest.key).to.eql('whale');
|
||||
expect(userQuest.progress.up).to.eql(10);
|
||||
expect(userQuest.progress.down).to.eql(0);
|
||||
expect(userQuest.progress.collectedItems).to.eql(0);
|
||||
expect(userQuest.progress.collectedItems).to.eql(5);
|
||||
expect(userQuest.completed).to.eql(null);
|
||||
});
|
||||
|
||||
@@ -1670,16 +1709,23 @@ describe('Group Model', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('sets user quest object to a clean state', async () => {
|
||||
it('updates participating members quest object to a clean state (except for progress)', async () => {
|
||||
await party.finishQuest(quest);
|
||||
|
||||
let updatedLeader = await User.findById(questLeader._id);
|
||||
questLeader = await User.findById(questLeader._id);
|
||||
participatingMember = await User.findById(participatingMember._id);
|
||||
|
||||
expect(updatedLeader.party.quest.completed).to.eql('whale');
|
||||
expect(updatedLeader.party.quest.progress.up).to.eql(0);
|
||||
expect(updatedLeader.party.quest.progress.down).to.eql(0);
|
||||
expect(updatedLeader.party.quest.progress.collectedItems).to.eql(0);
|
||||
expect(updatedLeader.party.quest.RSVPNeeded).to.eql(false);
|
||||
expect(questLeader.party.quest.completed).to.eql('whale');
|
||||
expect(questLeader.party.quest.progress.up).to.eql(10);
|
||||
expect(questLeader.party.quest.progress.down).to.eql(8);
|
||||
expect(questLeader.party.quest.progress.collectedItems).to.eql(5);
|
||||
expect(questLeader.party.quest.RSVPNeeded).to.eql(false);
|
||||
|
||||
expect(participatingMember.party.quest.completed).to.eql('whale');
|
||||
expect(participatingMember.party.quest.progress.up).to.eql(10);
|
||||
expect(participatingMember.party.quest.progress.down).to.eql(8);
|
||||
expect(participatingMember.party.quest.progress.collectedItems).to.eql(5);
|
||||
expect(participatingMember.party.quest.RSVPNeeded).to.eql(false);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
import {generateUser, translate as t} from '../../../../../helpers/api-integration/v3';
|
||||
import applePayments from '../../../../../../website/server/libs/payments/apple';
|
||||
|
||||
describe('payments : apple #norenewsubscribe', () => {
|
||||
let endpoint = '/iap/ios/norenew-subscribe';
|
||||
let sku = 'com.habitrpg.ios.habitica.subscription.3month';
|
||||
let user;
|
||||
|
||||
beforeEach(async () => {
|
||||
user = await generateUser();
|
||||
});
|
||||
|
||||
it('verifies sub key', async () => {
|
||||
await expect(user.post(endpoint)).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('missingSubscriptionCode'),
|
||||
});
|
||||
});
|
||||
|
||||
it('verifies receipt existence', async () => {
|
||||
await expect(user.post(endpoint, {
|
||||
sku,
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('missingReceipt'),
|
||||
});
|
||||
});
|
||||
|
||||
describe('success', () => {
|
||||
let subscribeStub;
|
||||
|
||||
beforeEach(async () => {
|
||||
subscribeStub = sinon.stub(applePayments, 'noRenewSubscribe').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
applePayments.noRenewSubscribe.restore();
|
||||
});
|
||||
|
||||
it('makes a purchase', async () => {
|
||||
user = await generateUser({
|
||||
'profile.name': 'sender',
|
||||
'purchased.plan.customerId': 'customer-id',
|
||||
'purchased.plan.planId': 'basic_3mo',
|
||||
'purchased.plan.lastBillingDate': new Date(),
|
||||
balance: 2,
|
||||
});
|
||||
|
||||
await user.post(endpoint, {
|
||||
sku,
|
||||
transaction: {receipt: 'receipt'},
|
||||
gift: {
|
||||
uuid: '1',
|
||||
},
|
||||
});
|
||||
|
||||
expect(subscribeStub).to.be.calledOnce;
|
||||
expect(subscribeStub.args[0][0].user._id).to.eql(user._id);
|
||||
expect(subscribeStub.args[0][0].sku).to.eql(sku);
|
||||
expect(subscribeStub.args[0][0].receipt).to.eql('receipt');
|
||||
expect(subscribeStub.args[0][0].headers['x-api-key']).to.eql(user.apiToken);
|
||||
expect(subscribeStub.args[0][0].headers['x-api-user']).to.eql(user._id);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import {generateUser} from '../../../../../helpers/api-integration/v3';
|
||||
import {generateUser, translate as t} from '../../../../../helpers/api-integration/v3';
|
||||
import applePayments from '../../../../../../website/server/libs/payments/apple';
|
||||
|
||||
describe('payments : apple #verify', () => {
|
||||
@@ -9,6 +9,14 @@ describe('payments : apple #verify', () => {
|
||||
user = await generateUser();
|
||||
});
|
||||
|
||||
it('verifies receipt existence', async () => {
|
||||
await expect(user.post(endpoint)).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('missingReceipt'),
|
||||
});
|
||||
});
|
||||
|
||||
describe('success', () => {
|
||||
let verifyStub;
|
||||
|
||||
@@ -31,10 +39,31 @@ describe('payments : apple #verify', () => {
|
||||
}});
|
||||
|
||||
expect(verifyStub).to.be.calledOnce;
|
||||
expect(verifyStub.args[0][0]._id).to.eql(user._id);
|
||||
expect(verifyStub.args[0][1]).to.eql('receipt');
|
||||
expect(verifyStub.args[0][2]['x-api-key']).to.eql(user.apiToken);
|
||||
expect(verifyStub.args[0][2]['x-api-user']).to.eql(user._id);
|
||||
expect(verifyStub.args[0][0].user._id).to.eql(user._id);
|
||||
expect(verifyStub.args[0][0].receipt).to.eql('receipt');
|
||||
expect(verifyStub.args[0][0].headers['x-api-key']).to.eql(user.apiToken);
|
||||
expect(verifyStub.args[0][0].headers['x-api-user']).to.eql(user._id);
|
||||
});
|
||||
|
||||
it('gifts a purchase', async () => {
|
||||
user = await generateUser({
|
||||
balance: 2,
|
||||
});
|
||||
|
||||
await user.post(endpoint, {
|
||||
transaction: {
|
||||
receipt: 'receipt',
|
||||
},
|
||||
gift: {
|
||||
uuid: '1',
|
||||
}});
|
||||
|
||||
expect(verifyStub).to.be.calledOnce;
|
||||
expect(verifyStub.args[0][0].user._id).to.eql(user._id);
|
||||
expect(verifyStub.args[0][0].receipt).to.eql('receipt');
|
||||
expect(verifyStub.args[0][0].gift.uuid).to.eql('1');
|
||||
expect(verifyStub.args[0][0].headers['x-api-key']).to.eql(user.apiToken);
|
||||
expect(verifyStub.args[0][0].headers['x-api-user']).to.eql(user._id);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
import {generateUser, translate as t} from '../../../../../helpers/api-integration/v3';
|
||||
import googlePayments from '../../../../../../website/server/libs/payments/google';
|
||||
|
||||
describe('payments : google #norenewsubscribe', () => {
|
||||
let endpoint = '/iap/android/norenew-subscribe';
|
||||
let sku = 'com.habitrpg.android.habitica.subscription.3month';
|
||||
let user;
|
||||
|
||||
beforeEach(async () => {
|
||||
user = await generateUser();
|
||||
});
|
||||
|
||||
it('verifies sub key', async () => {
|
||||
await expect(user.post(endpoint)).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('missingSubscriptionCode'),
|
||||
});
|
||||
});
|
||||
|
||||
it('verifies receipt existence', async () => {
|
||||
await expect(user.post(endpoint, {
|
||||
sku,
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('missingReceipt'),
|
||||
});
|
||||
});
|
||||
|
||||
describe('success', () => {
|
||||
let subscribeStub;
|
||||
|
||||
beforeEach(async () => {
|
||||
subscribeStub = sinon.stub(googlePayments, 'noRenewSubscribe').resolves({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
googlePayments.noRenewSubscribe.restore();
|
||||
});
|
||||
|
||||
it('makes a purchase', async () => {
|
||||
user = await generateUser({
|
||||
'profile.name': 'sender',
|
||||
'purchased.plan.customerId': 'customer-id',
|
||||
'purchased.plan.planId': 'basic_3mo',
|
||||
'purchased.plan.lastBillingDate': new Date(),
|
||||
balance: 2,
|
||||
});
|
||||
|
||||
await user.post(endpoint, {
|
||||
sku,
|
||||
transaction: {
|
||||
receipt: 'receipt',
|
||||
signature: 'signature',
|
||||
},
|
||||
});
|
||||
|
||||
expect(subscribeStub).to.be.calledOnce;
|
||||
expect(subscribeStub.args[0][0].user._id).to.eql(user._id);
|
||||
expect(subscribeStub.args[0][0].sku).to.eql(sku);
|
||||
expect(subscribeStub.args[0][0].receipt).to.eql('receipt');
|
||||
expect(subscribeStub.args[0][0].signature).to.eql('signature');
|
||||
expect(subscribeStub.args[0][0].headers['x-api-key']).to.eql(user.apiToken);
|
||||
expect(subscribeStub.args[0][0].headers['x-api-user']).to.eql(user._id);
|
||||
});
|
||||
|
||||
it('gifts a purchase', async () => {
|
||||
user = await generateUser({
|
||||
'profile.name': 'sender',
|
||||
'purchased.plan.customerId': 'customer-id',
|
||||
'purchased.plan.planId': 'basic_3mo',
|
||||
'purchased.plan.lastBillingDate': new Date(),
|
||||
balance: 2,
|
||||
});
|
||||
|
||||
await user.post(endpoint, {
|
||||
sku,
|
||||
transaction: {
|
||||
receipt: 'receipt',
|
||||
signature: 'signature',
|
||||
},
|
||||
gift: {
|
||||
uuid: '1',
|
||||
},
|
||||
});
|
||||
|
||||
expect(subscribeStub).to.be.calledOnce;
|
||||
expect(subscribeStub.args[0][0].user._id).to.eql(user._id);
|
||||
expect(subscribeStub.args[0][0].sku).to.eql(sku);
|
||||
expect(subscribeStub.args[0][0].receipt).to.eql('receipt');
|
||||
expect(subscribeStub.args[0][0].signature).to.eql('signature');
|
||||
expect(subscribeStub.args[0][0].headers['x-api-key']).to.eql(user.apiToken);
|
||||
expect(subscribeStub.args[0][0].headers['x-api-user']).to.eql(user._id);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import {generateUser} from '../../../../../helpers/api-integration/v3';
|
||||
import {generateUser, translate as t} from '../../../../../helpers/api-integration/v3';
|
||||
import googlePayments from '../../../../../../website/server/libs/payments/google';
|
||||
|
||||
describe('payments : google #verify', () => {
|
||||
@@ -9,6 +9,14 @@ describe('payments : google #verify', () => {
|
||||
user = await generateUser();
|
||||
});
|
||||
|
||||
it('verifies receipt existence', async () => {
|
||||
await expect(user.post(endpoint)).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('missingReceipt'),
|
||||
});
|
||||
});
|
||||
|
||||
describe('success', () => {
|
||||
let verifyStub;
|
||||
|
||||
@@ -30,11 +38,30 @@ describe('payments : google #verify', () => {
|
||||
});
|
||||
|
||||
expect(verifyStub).to.be.calledOnce;
|
||||
expect(verifyStub.args[0][0]._id).to.eql(user._id);
|
||||
expect(verifyStub.args[0][1]).to.eql('receipt');
|
||||
expect(verifyStub.args[0][2]).to.eql('signature');
|
||||
expect(verifyStub.args[0][3]['x-api-key']).to.eql(user.apiToken);
|
||||
expect(verifyStub.args[0][3]['x-api-user']).to.eql(user._id);
|
||||
expect(verifyStub.args[0][0].user._id).to.eql(user._id);
|
||||
expect(verifyStub.args[0][0].receipt).to.eql('receipt');
|
||||
expect(verifyStub.args[0][0].signature).to.eql('signature');
|
||||
expect(verifyStub.args[0][0].headers['x-api-key']).to.eql(user.apiToken);
|
||||
expect(verifyStub.args[0][0].headers['x-api-user']).to.eql(user._id);
|
||||
});
|
||||
|
||||
it('gifts a purchase', async () => {
|
||||
user = await generateUser({
|
||||
balance: 2,
|
||||
});
|
||||
|
||||
await user.post(endpoint, {
|
||||
transaction: {receipt: 'receipt', signature: 'signature'},
|
||||
gift: {uuid: '1'},
|
||||
});
|
||||
|
||||
expect(verifyStub).to.be.calledOnce;
|
||||
expect(verifyStub.args[0][0].user._id).to.eql(user._id);
|
||||
expect(verifyStub.args[0][0].receipt).to.eql('receipt');
|
||||
expect(verifyStub.args[0][0].signature).to.eql('signature');
|
||||
expect(verifyStub.args[0][0].gift.uuid).to.eql('1');
|
||||
expect(verifyStub.args[0][0].headers['x-api-key']).to.eql(user.apiToken);
|
||||
expect(verifyStub.args[0][0].headers['x-api-user']).to.eql(user._id);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
300
test/client/unit/specs/components/avatar.vue.test.js
Normal file
@@ -0,0 +1,300 @@
|
||||
import Avatar from 'client/components/avatar';
|
||||
import Vue from 'vue';
|
||||
import generateStore from 'client/store';
|
||||
|
||||
context('avatar.vue', () => {
|
||||
let Constructr;
|
||||
let vm;
|
||||
|
||||
beforeEach(() => {
|
||||
Constructr = Vue.extend(Avatar);
|
||||
|
||||
vm = new Constructr({
|
||||
propsData: {
|
||||
member: {
|
||||
stats: {
|
||||
buffs: {},
|
||||
},
|
||||
preferences: {
|
||||
hair: {},
|
||||
},
|
||||
items: {
|
||||
gear: {
|
||||
equipped: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}).$mount();
|
||||
|
||||
vm.$store = generateStore();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vm.$destroy();
|
||||
});
|
||||
|
||||
describe('hasClass', () => {
|
||||
beforeEach(() => {
|
||||
vm.member = {
|
||||
stats: { lvl: 17 },
|
||||
preferences: { disableClasses: true },
|
||||
flags: { classSelected: false },
|
||||
};
|
||||
});
|
||||
|
||||
it('accurately reports class status', () => {
|
||||
expect(vm.hasClass).to.equal(false);
|
||||
|
||||
vm.member.preferences.disableClasses = false;
|
||||
vm.member.flags.classSelected = true;
|
||||
|
||||
expect(vm.hasClass).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isBuffed', () => {
|
||||
beforeEach(() => {
|
||||
vm.member = {
|
||||
stats: {
|
||||
buffs: {},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it('accurately reports if buffed', () => {
|
||||
expect(vm.isBuffed).to.equal(undefined);
|
||||
|
||||
vm.member.stats.buffs = { str: 1 };
|
||||
|
||||
expect(vm.isBuffed).to.equal(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('paddingTop', () => {
|
||||
beforeEach(() => {
|
||||
vm.member = {
|
||||
items: {},
|
||||
};
|
||||
});
|
||||
|
||||
it('defaults to 28px', () => {
|
||||
vm.avatarOnly = true;
|
||||
expect(vm.paddingTop).to.equal('28px');
|
||||
});
|
||||
|
||||
it('is 24.5px if user has a pet', () => {
|
||||
vm.member.items = {
|
||||
currentPet: { name: 'Foo' },
|
||||
};
|
||||
|
||||
expect(vm.paddingTop).to.equal('24.5px');
|
||||
});
|
||||
|
||||
it('is 0px if user has a mount', () => {
|
||||
vm.member.items = {
|
||||
currentMount: { name: 'Bar' },
|
||||
};
|
||||
|
||||
expect(vm.paddingTop).to.equal('0px');
|
||||
});
|
||||
|
||||
it('can be overriden', () => {
|
||||
vm.overrideTopPadding = '27px';
|
||||
expect(vm.paddingTop).to.equal('27px');
|
||||
});
|
||||
});
|
||||
|
||||
describe('costumeClass', () => {
|
||||
beforeEach(() => {
|
||||
vm.member = {
|
||||
preferences: {},
|
||||
};
|
||||
});
|
||||
|
||||
it('returns if showing equiped gear', () => {
|
||||
expect(vm.costumeClass).to.equal('equipped');
|
||||
});
|
||||
it('returns if wearing a costume', () => {
|
||||
vm.member.preferences = { costume: true };
|
||||
expect(vm.costumeClass).to.equal('costume');
|
||||
});
|
||||
});
|
||||
|
||||
describe('visualBuffs', () => {
|
||||
it('returns an array of buffs', () => {
|
||||
vm.member = {
|
||||
stats: {
|
||||
class: 'Warrior',
|
||||
},
|
||||
};
|
||||
|
||||
expect(vm.visualBuffs).to.include({snowball: 'snowman'});
|
||||
expect(vm.visualBuffs).to.include({spookySparkles: 'ghost'});
|
||||
expect(vm.visualBuffs).to.include({shinySeed: 'avatar_floral_Warrior'});
|
||||
expect(vm.visualBuffs).to.include({seafoam: 'seafoam_star'});
|
||||
});
|
||||
});
|
||||
|
||||
describe('backgroundClass', () => {
|
||||
beforeEach(() => {
|
||||
vm.member.preferences = { background: 'pony' };
|
||||
});
|
||||
|
||||
it('shows the background', () => {
|
||||
expect(vm.backgroundClass).to.equal('background_pony');
|
||||
});
|
||||
|
||||
it('can be overridden', () => {
|
||||
vm.overrideAvatarGear = { background: 'character' };
|
||||
|
||||
expect(vm.backgroundClass).to.equal('background_character');
|
||||
});
|
||||
|
||||
it('returns to a blank string if not showing background', () => {
|
||||
vm.withBackground = false;
|
||||
vm.avatarOnly = true;
|
||||
|
||||
expect(vm.backgroundClass).to.equal('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('specialMountClass', () => {
|
||||
it('checks if riding a Kangaroo', () => {
|
||||
vm.member = {
|
||||
stats: {
|
||||
class: 'None',
|
||||
},
|
||||
items: {},
|
||||
};
|
||||
|
||||
expect(vm.specialMountClass).to.equal(undefined);
|
||||
|
||||
vm.member.items = {
|
||||
currentMount: ['Kangaroo'],
|
||||
};
|
||||
|
||||
expect(vm.specialMountClass).to.equal('offset-kangaroo');
|
||||
});
|
||||
});
|
||||
|
||||
describe('skinClass', () => {
|
||||
it('returns current skin color', () => {
|
||||
vm.member = {
|
||||
stats: {},
|
||||
preferences: {
|
||||
skin: 'blue',
|
||||
},
|
||||
};
|
||||
|
||||
expect(vm.skinClass).to.equal('skin_blue');
|
||||
});
|
||||
|
||||
it('returns if sleep or not', () => {
|
||||
vm.member = {
|
||||
stats: {},
|
||||
preferences: {
|
||||
skin: 'blue',
|
||||
sleep: false,
|
||||
},
|
||||
};
|
||||
|
||||
expect(vm.skinClass).to.equal('skin_blue');
|
||||
|
||||
vm.member.preferences.sleep = true;
|
||||
|
||||
expect(vm.skinClass).to.equal('skin_blue_sleep');
|
||||
});
|
||||
});
|
||||
|
||||
context('methods', () => {
|
||||
describe('getGearClass', () => {
|
||||
beforeEach(() => {
|
||||
vm.member = {
|
||||
items: {
|
||||
gear: {
|
||||
equipped: { Hat: 'Fancy Tophat' },
|
||||
},
|
||||
},
|
||||
preferences: { costume: false },
|
||||
};
|
||||
});
|
||||
|
||||
it('returns undefined if no match', () => {
|
||||
expect(vm.getGearClass('foo')).to.equal(undefined);
|
||||
});
|
||||
|
||||
it('returns the matching gear', () => {
|
||||
expect(vm.getGearClass('Hat')).to.equal('Fancy Tophat');
|
||||
});
|
||||
|
||||
it('can be overridden', () => {
|
||||
vm.overrideAvatarGear = { Hat: 'Dapper Bowler' };
|
||||
|
||||
expect(vm.getGearClass('Hat')).to.equal('Dapper Bowler');
|
||||
});
|
||||
});
|
||||
|
||||
describe('hideGear', () => {
|
||||
it('returns no weapon equipped', () => {
|
||||
vm.member.items.gear.equipped = {};
|
||||
expect(vm.hideGear('weapon')).to.equal(false);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vm.member = {
|
||||
items: {
|
||||
gear: {
|
||||
equipped: {
|
||||
weapon: {
|
||||
baseWeapon: 'Spoon',
|
||||
twoHanded: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
preferences: { costume: false },
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
describe('show avatar', () => {
|
||||
beforeEach(() => {
|
||||
vm.member = {
|
||||
stats: {
|
||||
buffs: {
|
||||
snowball: false,
|
||||
seafoam: false,
|
||||
spookySparkles: false,
|
||||
shinySeed: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
it('does if not showing visual buffs', () => {
|
||||
expect(vm.showAvatar()).to.equal(true);
|
||||
|
||||
let buffs = vm.member.stats.buffs;
|
||||
|
||||
buffs.snowball = true;
|
||||
expect(vm.showAvatar()).to.equal(false);
|
||||
|
||||
buffs.snowball = false;
|
||||
buffs.spookySparkles = true;
|
||||
expect(vm.showAvatar()).to.equal(false);
|
||||
|
||||
buffs.spookySparkles = false;
|
||||
buffs.shinySeed = true;
|
||||
expect(vm.showAvatar()).to.equal(false);
|
||||
|
||||
buffs.shinySeed = false;
|
||||
buffs.seafoam = true;
|
||||
expect(vm.showAvatar()).to.equal(false);
|
||||
|
||||
buffs.seafoam = false;
|
||||
vm.showVisualBuffs = false;
|
||||
expect(vm.showAvatar()).to.equal(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
76
test/client/unit/specs/store/getters/user/user.test.js
Normal file
@@ -0,0 +1,76 @@
|
||||
import { data, gems, buffs, preferences, tasksOrder } from 'client/store/getters/user';
|
||||
|
||||
context('user getters', () => {
|
||||
describe('data', () => {
|
||||
it('returns the user\'s data', () => {
|
||||
expect(data({
|
||||
state: {
|
||||
user: {
|
||||
data: {
|
||||
lvl: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
}).lvl).to.equal(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('gems', () => {
|
||||
it('returns the user\'s gems', () => {
|
||||
expect(gems({
|
||||
state: {
|
||||
user: {
|
||||
data: { balance: 4.5 },
|
||||
},
|
||||
},
|
||||
})).to.equal(18);
|
||||
});
|
||||
});
|
||||
|
||||
describe('buffs', () => {
|
||||
it('returns the user\'s buffs', () => {
|
||||
expect(buffs({
|
||||
state: {
|
||||
user: {
|
||||
data: {
|
||||
stats: {
|
||||
buffs: [1],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})(0)).to.equal(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('preferences', () => {
|
||||
it('returns the user\'s preferences', () => {
|
||||
expect(preferences({
|
||||
state: {
|
||||
user: {
|
||||
data: {
|
||||
preferences: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
})).to.equal(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('tasksOrder', () => {
|
||||
it('returns the user\'s tasksOrder', () => {
|
||||
expect(tasksOrder({
|
||||
state: {
|
||||
user: {
|
||||
tasksOrder: {
|
||||
masters: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
})('master')).to.equal(1);
|
||||
|
||||
expect(tasksOrder()).to.not.equal('null');
|
||||
expect(tasksOrder()).to.not.equal('undefined');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,13 +0,0 @@
|
||||
import { gems as userGems } from 'client/store/getters/user';
|
||||
|
||||
describe('userGems getter', () => {
|
||||
it('returns the user\'s gems', () => {
|
||||
expect(userGems({
|
||||
state: {
|
||||
user: {
|
||||
data: {balance: 4.5},
|
||||
},
|
||||
},
|
||||
})).to.equal(18);
|
||||
});
|
||||
});
|
||||
20
test/helpers/mongoose.helper.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import mongoose from 'mongoose';
|
||||
|
||||
export async function mockFindById (response) {
|
||||
const mockFind = {
|
||||
select () {
|
||||
return this;
|
||||
},
|
||||
lean () {
|
||||
return this;
|
||||
},
|
||||
exec () {
|
||||
return Promise.resolve(response);
|
||||
},
|
||||
};
|
||||
sinon.stub(mongoose.Model, 'findById').returns(mockFind);
|
||||
}
|
||||
|
||||
export function restoreFindById () {
|
||||
return mongoose.Model.findById.restore();
|
||||
}
|
||||
@@ -16,18 +16,24 @@ div
|
||||
router-view(v-if="!isUserLoggedIn || isStaticPage")
|
||||
template(v-else)
|
||||
template(v-if="isUserLoaded")
|
||||
div.resting-banner(v-show="showRestingBanner", ref="restingBanner")
|
||||
.resting-banner(v-show="showRestingBanner", ref="restingBanner")
|
||||
span.content
|
||||
span.label.d-inline.d-sm-none {{ $t('innCheckOutBannerShort') }}
|
||||
span.label.d-none.d-sm-inline {{ $t('innCheckOutBanner') }}
|
||||
span.separator |
|
||||
span.resume(@click="resumeDamage()") {{ $t('resumeDamage') }}
|
||||
div.closepadding(@click="hideBanner()")
|
||||
.closepadding(@click="hideBanner()")
|
||||
span.svg-icon.inline.icon-10(aria-hidden="true", v-html="icons.close")
|
||||
.g1g1-banner.d-flex.justify-content-center.align-items-center(v-if="!giftingHidden")
|
||||
.svg-icon.svg-gifts.left-gift(v-html="icons.gifts")
|
||||
router-link(:to="{name: 'subscription'}") {{ $t('g1g1Announcement') }}
|
||||
.svg-icon.svg-gifts.right-gift(v-html="icons.gifts")
|
||||
.closepadding(@click="hideGiftingBanner()")
|
||||
span.svg-icon.inline.icon-10(aria-hidden="true", v-html="icons.close")
|
||||
notifications-display
|
||||
app-menu(:class='{"restingInn": showRestingBanner}' :style="{ marginTop: bannerHeight + 'px' }")
|
||||
app-menu
|
||||
.container-fluid
|
||||
app-header(:class='{"restingInn": showRestingBanner}')
|
||||
app-header
|
||||
buyModal(
|
||||
:item="selectedItemToBuy || {}",
|
||||
:withPin="true",
|
||||
@@ -50,6 +56,13 @@ div
|
||||
<style lang='scss' scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
#app {
|
||||
height: calc(100% - 56px); /* 56px is the menu */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
#loading-screen-inapp {
|
||||
#melior {
|
||||
margin: 0 auto;
|
||||
@@ -79,6 +92,46 @@ div
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.container-fluid {
|
||||
overflow-x: hidden;
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
.g1g1-banner {
|
||||
width: 100%;
|
||||
min-height: 2.5rem;
|
||||
background-color: #34b5c1;
|
||||
|
||||
a {
|
||||
color: $white;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.closepadding {
|
||||
margin: 11px 24px;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
right: 0;
|
||||
top: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.left-gift {
|
||||
margin: auto 1rem auto auto;
|
||||
}
|
||||
|
||||
.right-gift {
|
||||
margin: auto auto auto 1rem;
|
||||
filter: FlipH;
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.svg-gifts {
|
||||
width: 4.6rem;
|
||||
}
|
||||
}
|
||||
|
||||
.notification {
|
||||
border-radius: 1000px;
|
||||
background-color: $green-10;
|
||||
@@ -89,42 +142,10 @@ div
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
|
||||
.container-fluid {
|
||||
overflow-x: hidden;
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
#app {
|
||||
height: calc(100% - 56px); /* 56px is the menu */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang='scss'>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
/* @TODO: The modal-open class is not being removed. Let's try this for now */
|
||||
.modal {
|
||||
overflow-y: scroll !important;
|
||||
}
|
||||
|
||||
.modal-backdrop.show {
|
||||
opacity: .9 !important;
|
||||
background-color: $purple-100 !important;
|
||||
}
|
||||
|
||||
/* Push progress bar above modals */
|
||||
#nprogress .bar {
|
||||
z-index: 1600 !important; /* Must stay above nav bar */
|
||||
}
|
||||
|
||||
.resting-banner {
|
||||
width: 100%;
|
||||
min-height: 40px;
|
||||
background-color: $blue-10;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
z-index: 1300;
|
||||
display: flex;
|
||||
@@ -140,14 +161,10 @@ div
|
||||
.closepadding {
|
||||
margin: 11px 24px;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
position: relative;
|
||||
right: 0;
|
||||
top: 0;
|
||||
cursor: pointer;
|
||||
|
||||
span svg path {
|
||||
stroke: $blue-500;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
@@ -170,6 +187,30 @@ div
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang='scss'>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.closepadding span svg path {
|
||||
stroke: #FFF;
|
||||
opacity: 0.48;
|
||||
}
|
||||
|
||||
/* @TODO: The modal-open class is not being removed. Let's try this for now */
|
||||
.modal {
|
||||
overflow-y: scroll !important;
|
||||
}
|
||||
|
||||
.modal-backdrop.show {
|
||||
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';
|
||||
@@ -189,8 +230,9 @@ import amazonPaymentsModal from 'client/components/payments/amazonModal';
|
||||
import paymentsSuccessModal from 'client/components/payments/successModal';
|
||||
|
||||
import spellsMixin from 'client/mixins/spells';
|
||||
import { CONSTANTS, getLocalSetting, removeLocalSetting } from 'client/libs/userlocalManager';
|
||||
import { CONSTANTS, getLocalSetting, removeLocalSetting, setLocalSetting } from 'client/libs/userlocalManager';
|
||||
|
||||
import gifts from 'assets/svg/gifts.svg';
|
||||
import svgClose from 'assets/svg/close.svg';
|
||||
import bannedAccountModal from 'client/components/bannedAccountModal';
|
||||
|
||||
@@ -215,6 +257,7 @@ export default {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
close: svgClose,
|
||||
gifts,
|
||||
}),
|
||||
selectedItemToBuy: null,
|
||||
selectedSpellToBuy: null,
|
||||
@@ -226,6 +269,7 @@ export default {
|
||||
currentTipNumber: 0,
|
||||
bannerHidden: false,
|
||||
bannerHeight: 0,
|
||||
giftingHidden: getLocalSetting(CONSTANTS.keyConstants.GIFTING_BANNER_DISPLAY) === 'dismissed',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -423,14 +467,6 @@ export default {
|
||||
|
||||
this.hideLoadingScreen();
|
||||
|
||||
window.addEventListener('resize', this.setBannerOffset);
|
||||
// Adjust the positioning of the header banners
|
||||
this.$watch('showRestingBanner', () => {
|
||||
this.$nextTick(() => {
|
||||
this.setBannerOffset();
|
||||
});
|
||||
}, {immediate: true});
|
||||
|
||||
// Adjust the timezone offset
|
||||
if (this.user.preferences.timezoneOffset !== this.browserTimezoneOffset) {
|
||||
this.$store.dispatch('user:set', {
|
||||
@@ -443,7 +479,7 @@ export default {
|
||||
appState = JSON.parse(appState);
|
||||
if (appState.paymentCompleted) {
|
||||
removeLocalSetting(CONSTANTS.savedAppStateValues.SAVED_APP_STATE);
|
||||
this.$root.$emit('bv::show::modal', 'payments-success-modal');
|
||||
this.$root.$emit('habitica:payment-success', appState);
|
||||
}
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
@@ -465,7 +501,6 @@ export default {
|
||||
this.$root.$off('bv::show::modal');
|
||||
this.$root.$off('buyModal::showItem');
|
||||
this.$root.$off('selectMembersModal::showItem');
|
||||
window.removeEventListener('resize', this.setBannerOffset);
|
||||
},
|
||||
mounted () {
|
||||
// Remove the index.html loading screen and now show the inapp loading
|
||||
@@ -624,22 +659,14 @@ export default {
|
||||
},
|
||||
hideBanner () {
|
||||
this.bannerHidden = true;
|
||||
this.setBannerOffset();
|
||||
},
|
||||
hideGiftingBanner () {
|
||||
setLocalSetting(CONSTANTS.keyConstants.GIFTING_BANNER_DISPLAY, 'dismissed');
|
||||
this.giftingHidden = true;
|
||||
},
|
||||
resumeDamage () {
|
||||
this.$store.dispatch('user:sleep');
|
||||
},
|
||||
setBannerOffset () {
|
||||
let contentPlacement = 0;
|
||||
if (this.showRestingBanner && this.$refs.restingBanner !== undefined) {
|
||||
contentPlacement = this.$refs.restingBanner.clientHeight;
|
||||
}
|
||||
this.bannerHeight = contentPlacement;
|
||||
let smartBanner = document.getElementsByClassName('smartbanner')[0];
|
||||
if (smartBanner !== undefined) {
|
||||
smartBanner.style.top = `${contentPlacement}px`;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -1,96 +1,72 @@
|
||||
.achievement-costumeContest6x {
|
||||
.promo_armoire_backgrounds_201901 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -1136px -438px;
|
||||
width: 144px;
|
||||
height: 156px;
|
||||
}
|
||||
.promo_alligator {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px 0px;
|
||||
width: 480px;
|
||||
height: 360px;
|
||||
}
|
||||
.promo_animal_tails {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -994px 0px;
|
||||
width: 141px;
|
||||
height: 441px;
|
||||
}
|
||||
.promo_armoire_backgrounds_201812 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px -723px;
|
||||
background-position: 0px -148px;
|
||||
width: 423px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_bird_buddies_bundle {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -424px -723px;
|
||||
background-position: -424px 0px;
|
||||
width: 420px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_frost_potions {
|
||||
.promo_g1g1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -421px -871px;
|
||||
width: 417px;
|
||||
height: 147px;
|
||||
background-position: -241px -444px;
|
||||
width: 237px;
|
||||
height: 150px;
|
||||
}
|
||||
.promo_ios {
|
||||
.promo_npc_alex {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px -361px;
|
||||
width: 375px;
|
||||
height: 361px;
|
||||
background-position: -403px -296px;
|
||||
width: 162px;
|
||||
height: 138px;
|
||||
}
|
||||
.promo_mystery_201811 {
|
||||
.promo_seasonal_shop {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -1136px -142px;
|
||||
width: 282px;
|
||||
height: 147px;
|
||||
background-position: -566px -296px;
|
||||
width: 162px;
|
||||
height: 138px;
|
||||
}
|
||||
.promo_piyo {
|
||||
.promo_snow_potions {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -1136px -290px;
|
||||
width: 279px;
|
||||
background-position: 0px 0px;
|
||||
width: 423px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_take_this {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -1281px -438px;
|
||||
background-position: -729px -296px;
|
||||
width: 96px;
|
||||
height: 69px;
|
||||
}
|
||||
.promo_turkey_day_2018 {
|
||||
.promo_winter_wonderland_2019 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px -871px;
|
||||
background-position: 0px -296px;
|
||||
width: 402px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_wintery_skins {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -424px -148px;
|
||||
width: 420px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_veteran_pets {
|
||||
.customize-option.promo_wintery_skins {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -1136px 0px;
|
||||
width: 363px;
|
||||
height: 141px;
|
||||
background-position: -449px -163px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
.scene_hiking {
|
||||
.scene_starting_over {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -481px -420px;
|
||||
width: 258px;
|
||||
height: 258px;
|
||||
background-position: -479px -444px;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.scene_nametag {
|
||||
.scene_todo_list {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -481px 0px;
|
||||
width: 512px;
|
||||
height: 208px;
|
||||
}
|
||||
.scene_sleep {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -481px -209px;
|
||||
width: 390px;
|
||||
height: 210px;
|
||||
}
|
||||
.scene_veteran_pets {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -1136px -595px;
|
||||
width: 242px;
|
||||
height: 62px;
|
||||
background-position: 0px -444px;
|
||||
width: 240px;
|
||||
height: 195px;
|
||||
}
|
||||
|
||||
@@ -1,402 +1,402 @@
|
||||
.quest_TEMPLATE_FOR_MISSING_IMAGE {
|
||||
.npc_matt {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -502px -1546px;
|
||||
width: 221px;
|
||||
height: 39px;
|
||||
background-position: -597px -1535px;
|
||||
width: 195px;
|
||||
height: 138px;
|
||||
}
|
||||
.background_dysheartener {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px 0px;
|
||||
width: 306px;
|
||||
height: 202px;
|
||||
}
|
||||
.banner_flair_dysheartener {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1963px -836px;
|
||||
width: 69px;
|
||||
height: 18px;
|
||||
}
|
||||
.phobia_dysheartener {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1187px -880px;
|
||||
width: 201px;
|
||||
height: 195px;
|
||||
}
|
||||
.quest_alligator {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1627px -1079px;
|
||||
width: 201px;
|
||||
height: 213px;
|
||||
}
|
||||
.quest_armadillo {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -435px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_atom1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1105px -1315px;
|
||||
width: 250px;
|
||||
height: 150px;
|
||||
}
|
||||
.quest_atom2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -389px -1535px;
|
||||
width: 207px;
|
||||
height: 138px;
|
||||
}
|
||||
.quest_atom3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -747px -440px;
|
||||
width: 216px;
|
||||
height: 180px;
|
||||
}
|
||||
.quest_axolotl {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -747px -220px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_badger {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -655px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_basilist {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1844px -392px;
|
||||
width: 189px;
|
||||
height: 141px;
|
||||
}
|
||||
.quest_beetle {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1627px -1293px;
|
||||
width: 204px;
|
||||
height: 201px;
|
||||
}
|
||||
.quest_bunny {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1322px -1112px;
|
||||
background-position: -967px -660px;
|
||||
width: 210px;
|
||||
height: 186px;
|
||||
}
|
||||
.quest_butterfly {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1320px -440px;
|
||||
background-position: -967px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_cheetah {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -220px -892px;
|
||||
background-position: -967px -220px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_cow {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px 0px;
|
||||
background-position: 0px -1535px;
|
||||
width: 174px;
|
||||
height: 213px;
|
||||
}
|
||||
.quest_dilatory {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -220px -232px;
|
||||
background-position: -220px -875px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_dilatoryDistress1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1540px -1085px;
|
||||
background-position: -1627px -868px;
|
||||
width: 210px;
|
||||
height: 210px;
|
||||
}
|
||||
.quest_dilatoryDistress2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -573px;
|
||||
background-position: -1844px -534px;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.quest_dilatoryDistress3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -660px -220px;
|
||||
background-position: -880px -875px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_dilatory_derby {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -232px;
|
||||
background-position: 0px -875px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_dustbunnies {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -452px;
|
||||
background-position: -1187px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_egg {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -214px;
|
||||
background-position: -1844px -184px;
|
||||
width: 165px;
|
||||
height: 207px;
|
||||
}
|
||||
.quest_evilsanta {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -1026px;
|
||||
background-position: -1844px -836px;
|
||||
width: 118px;
|
||||
height: 131px;
|
||||
}
|
||||
.quest_evilsanta2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -660px -452px;
|
||||
background-position: -1187px -660px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_falcon {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -880px 0px;
|
||||
background-position: 0px -1095px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_ferret {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -880px -220px;
|
||||
background-position: -307px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_frog {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1100px -1112px;
|
||||
background-position: -660px -1315px;
|
||||
width: 221px;
|
||||
height: 213px;
|
||||
}
|
||||
.quest_ghost_stag {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -672px;
|
||||
background-position: -660px -1095px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_goldenknight1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -220px -672px;
|
||||
background-position: -880px -1095px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_goldenknight2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -251px -1546px;
|
||||
background-position: -1356px -1315px;
|
||||
width: 250px;
|
||||
height: 150px;
|
||||
}
|
||||
.quest_goldenknight3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px 0px;
|
||||
background-position: 0px -203px;
|
||||
width: 219px;
|
||||
height: 231px;
|
||||
}
|
||||
.quest_gryphon {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1097px -1332px;
|
||||
background-position: -307px -220px;
|
||||
width: 216px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_guineapig {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1100px 0px;
|
||||
background-position: -1407px -440px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_harpy {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1100px -220px;
|
||||
background-position: -1407px -660px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_hedgehog {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -220px -1332px;
|
||||
background-position: -1407px -1100px;
|
||||
width: 219px;
|
||||
height: 186px;
|
||||
}
|
||||
.quest_hippo {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1100px -660px;
|
||||
background-position: 0px -1315px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_horse {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -892px;
|
||||
background-position: -220px -1315px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_kangaroo {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -220px 0px;
|
||||
background-position: -1407px -880px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_kraken {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -880px -1332px;
|
||||
background-position: -527px -220px;
|
||||
width: 216px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_lostMasterclasser1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -660px -892px;
|
||||
background-position: -1100px -1095px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_lostMasterclasser2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -880px -892px;
|
||||
background-position: -440px -1095px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_lostMasterclasser3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1100px -892px;
|
||||
background-position: -1187px -220px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_mayhemMistiflying1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -724px;
|
||||
background-position: -1844px -685px;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.quest_mayhemMistiflying2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1320px -220px;
|
||||
background-position: -440px -875px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_mayhemMistiflying3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -660px -672px;
|
||||
background-position: -660px -655px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_monkey {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1320px -660px;
|
||||
background-position: -440px -655px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_moon1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1540px -868px;
|
||||
background-position: -1627px -651px;
|
||||
width: 216px;
|
||||
height: 216px;
|
||||
}
|
||||
.quest_moon2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -1112px;
|
||||
background-position: -220px -655px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_moon3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -220px -1112px;
|
||||
background-position: -747px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_moonstone1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -440px -1112px;
|
||||
background-position: -527px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_moonstone2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -660px -1112px;
|
||||
background-position: -1407px -220px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_moonstone3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1320px -880px;
|
||||
background-position: -440px -1315px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_nudibranch {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1540px -651px;
|
||||
background-position: -1627px -217px;
|
||||
width: 216px;
|
||||
height: 216px;
|
||||
}
|
||||
.quest_octopus {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -440px -1332px;
|
||||
background-position: -882px -1315px;
|
||||
width: 222px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_owl {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1100px -440px;
|
||||
background-position: -1187px -440px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_peacock {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1540px -434px;
|
||||
background-position: -1627px 0px;
|
||||
width: 216px;
|
||||
height: 216px;
|
||||
}
|
||||
.quest_penguin {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -1697px;
|
||||
background-position: -1844px 0px;
|
||||
width: 190px;
|
||||
height: 183px;
|
||||
}
|
||||
.quest_pterodactyl {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -880px -440px;
|
||||
background-position: -660px -875px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_rat {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -660px 0px;
|
||||
background-position: -967px -440px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_rock {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1540px 0px;
|
||||
background-position: -1627px -434px;
|
||||
width: 216px;
|
||||
height: 216px;
|
||||
}
|
||||
.quest_rooster {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1531px -1332px;
|
||||
background-position: -175px -1535px;
|
||||
width: 213px;
|
||||
height: 174px;
|
||||
}
|
||||
.quest_sabretooth {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -880px -1112px;
|
||||
background-position: -440px -435px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_seaserpent {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -440px -232px;
|
||||
background-position: -220px -435px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_sheep {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -880px -672px;
|
||||
background-position: -220px -1095px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_slime {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1320px 0px;
|
||||
background-position: -1407px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_sloth {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -440px -892px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_snail {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -1332px;
|
||||
width: 219px;
|
||||
height: 213px;
|
||||
}
|
||||
.quest_snake {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1314px -1332px;
|
||||
width: 216px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_spider {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -1546px;
|
||||
width: 250px;
|
||||
height: 150px;
|
||||
}
|
||||
.quest_squirrel {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -440px -672px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_stoikalmCalamity1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -875px;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.quest_stoikalmCalamity2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -440px -452px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_stoikalmCalamity3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -220px -452px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_taskwoodsTerror1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -422px;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.quest_taskwoodsTerror2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1540px -217px;
|
||||
width: 216px;
|
||||
height: 216px;
|
||||
}
|
||||
.quest_taskwoodsTerror3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -440px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_treeling {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -663px -1332px;
|
||||
width: 216px;
|
||||
height: 177px;
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 208 KiB After Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 537 KiB After Width: | Height: | Size: 545 KiB |
|
Before Width: | Height: | Size: 519 KiB After Width: | Height: | Size: 532 KiB |
|
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 426 KiB After Width: | Height: | Size: 393 KiB |
|
Before Width: | Height: | Size: 206 KiB After Width: | Height: | Size: 279 KiB |
|
Before Width: | Height: | Size: 154 KiB After Width: | Height: | Size: 159 KiB |
|
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 145 KiB |
|
Before Width: | Height: | Size: 134 KiB After Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 169 KiB After Width: | Height: | Size: 168 KiB |
|
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 146 KiB After Width: | Height: | Size: 152 KiB |
|
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 155 KiB |
|
Before Width: | Height: | Size: 79 KiB After Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 178 KiB After Width: | Height: | Size: 181 KiB |
|
Before Width: | Height: | Size: 162 KiB After Width: | Height: | Size: 160 KiB |
|
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 67 KiB After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 123 KiB After Width: | Height: | Size: 123 KiB |
|
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 125 KiB |
|
Before Width: | Height: | Size: 137 KiB After Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 117 KiB |
@@ -2,8 +2,8 @@
|
||||
// possible values are: normal, fall, habitoween, thanksgiving, winter, nye, birthday, valentines, spring, summer
|
||||
// more to be added on future seasons
|
||||
|
||||
$npc_market_flavor: 'normal';
|
||||
$npc_quests_flavor: 'normal';
|
||||
$npc_seasonal_flavor: 'normal';
|
||||
$npc_timetravelers_flavor: 'normal';
|
||||
$npc_tavern_flavor: 'normal';
|
||||
$npc_market_flavor: 'winter';
|
||||
$npc_quests_flavor: 'winter';
|
||||
$npc_seasonal_flavor: 'winter';
|
||||
$npc_timetravelers_flavor: 'winter';
|
||||
$npc_tavern_flavor: 'winter';
|
||||
|
||||
1
website/client/assets/svg/drag_indicator.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/></svg>
|
||||
|
After Width: | Height: | Size: 431 B |
44
website/client/assets/svg/gifts.svg
Normal file
@@ -0,0 +1,44 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="73" height="27" viewBox="0 0 73 27">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path fill="#8EEDF6" d="M4.333 9.757l2.166-.554-1.742-1.401-.554-2.166-1.401 1.742-2.166.554 1.742 1.4.554 2.167zM70.333 5.757l2.166-.554-1.742-1.401-.554-2.166-1.401 1.742-2.166.554 1.742 1.4.554 2.167zM37.147 5.518l2.573.428-1.202-2.315.428-2.574-2.315 1.202-2.574-.427 1.202 2.315-.427 2.573zM68.735 22.132l2.367 1.812.03-2.981 1.812-2.368-2.981-.03-2.368-1.812-.03 2.982-1.812 2.367zM33.676 23.656l1.839.305-.859-1.653.305-1.839-1.653.859-1.839-.305.859 1.653-.305 1.839zM10.695 25.362l.805 1.68.862-1.651 1.68-.804-1.651-.862-.804-1.681-.862 1.652-1.681.804z"/>
|
||||
<path fill="#F8F9F9" d="M21.862 9.542l5.914-1.585 2.219 8.28-5.914 1.584z"/>
|
||||
<path fill="#DDF3F3" d="M15.949 11.126l5.913-1.584 2.219 8.28-5.914 1.584z"/>
|
||||
<path fill="#FFA624" d="M20.68 9.859l1.182-.317 2.219 8.28-1.183.316z"/>
|
||||
<path fill="#FFBE5D" d="M21.862 9.542l1.183-.317 2.219 8.28-1.183.316z"/>
|
||||
<path fill="#EE9109" d="M22.581 16.955l1.183-.317.317 1.183-1.183.317zM20.68 9.859l1.182-.317.317 1.183-1.182.317z"/>
|
||||
<path fill="#C1E9E9" d="M15.949 11.126l4.73-1.267.318 1.183-4.732 1.267zM17.85 18.223l4.731-1.268.317 1.183-4.731 1.268z"/>
|
||||
<path fill="#DDF3F3" d="M23.045 9.225l4.731-1.268.317 1.183-4.73 1.268zM24.947 16.322l4.73-1.268.318 1.183-4.731 1.267z"/>
|
||||
<path fill="#FFA624" d="M23.764 16.638l1.183-.316.317 1.182-1.183.317zM21.862 9.542l1.183-.317.317 1.183-1.183.317z"/>
|
||||
<g>
|
||||
<path stroke="#FFA624" stroke-width="1.5" d="M21.737 3.348c-.295-1.038-1.009-2.02-2.008-2.204-1-.184-1.69.542-1.495 1.297.195.755.88.984 3.075 1.916.623.264.723.03.428-1.009z"/>
|
||||
<path stroke="#FFBE5D" stroke-width="1.5" d="M24.307 3.71c.57-.918 1.527-1.664 2.538-1.565 1.012.098 1.475.986 1.08 1.658-.396.671-1.117.703-3.484.994-.672.083-.703-.17-.134-1.088z"/>
|
||||
<path fill="#EE9109" d="M23.129 2.769c-1.968-.277-1.106 2.141-.317 2.252.79.111 2.285-1.976.317-2.252z"/>
|
||||
<path fill="#F8F9F9" d="M22.862 4.665l7.276 1.022-.511 3.638-7.276-1.022z"/>
|
||||
<path fill="#DDF3F3" d="M15.587 3.642l7.275 1.023-.51 3.638-7.276-1.023z"/>
|
||||
<path fill="#FFBE5D" d="M20.437 4.324l4.85.682-.51 3.638-4.85-.682z"/>
|
||||
<path fill="#FFA624" d="M20.437 4.324l2.425.341-.51 3.638-2.426-.341z"/>
|
||||
<path fill="#FFA624" d="M22.862 4.665l2.426.34-.17 1.213-2.426-.34z"/>
|
||||
<path fill="#EE9109" d="M20.437 4.324l2.425.341-.17 1.213-2.425-.341z"/>
|
||||
<path fill="#C1E9E9" d="M15.246 6.068l4.85.681-.17 1.213-4.85-.682z"/>
|
||||
<path fill="#DDF3F3" d="M24.947 7.431l4.85.682-.17 1.212-4.85-.681z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path stroke="#FFA624" stroke-width="1.5" d="M49.696 7.04c-.549-1.24-1.609-2.337-2.885-2.391-1.276-.054-2.007.969-1.632 1.874.374.905 1.266 1.071 4.16 1.847.822.22.905-.09.357-1.33z"/>
|
||||
<path stroke="#FFBE5D" stroke-width="1.5" d="M52.956 7.04c.548-1.24 1.609-2.337 2.885-2.391 1.276-.054 2.007.969 1.632 1.874-.374.905-1.266 1.071-4.16 1.847-.822.22-.905-.09-.357-1.33z"/>
|
||||
<path fill="#EE9109" d="M51.326 6.075c-2.497 0-1.002 2.858 0 2.858s2.497-2.858 0-2.858z"/>
|
||||
<path fill="#F8F9F9" d="M51.326 8.481h9.23v4.616h-9.23z"/>
|
||||
<path fill="#DDF3F3" d="M42.095 8.481h9.23v4.616h-9.23z"/>
|
||||
<path fill="#FFBE5D" d="M48.249 8.481h6.154v4.616h-6.154z"/>
|
||||
<path fill="#FFA624" d="M48.249 8.481h3.077v4.616h-3.077zM51.326 8.481h3.077v1.539h-3.077z"/>
|
||||
<path fill="#EE9109" d="M48.249 8.481h3.077v1.539h-3.077z"/>
|
||||
<path fill="#F8F9F9" d="M51.326 13.097h7.692v10.769h-7.692z"/>
|
||||
<path fill="#DDF3F3" d="M43.634 13.097h7.692v10.769h-7.692z"/>
|
||||
<path fill="#FFA624" d="M49.787 13.097h1.538v10.769h-1.538z"/>
|
||||
<path fill="#FFBE5D" d="M51.326 13.097h1.538v10.769h-1.538z"/>
|
||||
<path fill="#EE9109" d="M49.787 22.327h1.539v1.539h-1.539zM49.787 13.097h1.539v1.538h-1.539z"/>
|
||||
<path fill="#C1E9E9" d="M43.634 13.097h6.153v1.538h-6.153zM42.095 11.558h6.154v1.539h-6.154zM43.634 22.327h6.153v1.539h-6.153z"/>
|
||||
<path fill="#DDF3F3" d="M52.864 13.097h6.154v1.538h-6.154zM54.403 11.558h6.154v1.539h-6.154zM52.864 22.327h6.154v1.539h-6.154z"/>
|
||||
<path fill="#FFA624" d="M51.326 22.327h1.538v1.539h-1.538zM51.326 13.097h1.538v1.538h-1.538z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.4 KiB |
@@ -164,30 +164,30 @@ export default {
|
||||
classGear (heroClass) {
|
||||
if (heroClass === 'rogue') {
|
||||
return {
|
||||
armor: 'armor_rogue_5',
|
||||
head: 'head_rogue_5',
|
||||
shield: 'shield_rogue_6',
|
||||
weapon: 'weapon_rogue_6',
|
||||
armor: 'armor_special_winter2019Rogue',
|
||||
head: 'head_special_winter2019Rogue',
|
||||
shield: 'shield_special_winter2019Rogue',
|
||||
weapon: 'weapon_special_winter2019Rogue',
|
||||
};
|
||||
} else if (heroClass === 'wizard') {
|
||||
return {
|
||||
armor: 'armor_wizard_5',
|
||||
head: 'head_wizard_5',
|
||||
weapon: 'weapon_wizard_6',
|
||||
armor: 'armor_special_winter2019Mage',
|
||||
head: 'head_special_winter2019Mage',
|
||||
weapon: 'weapon_special_winter2019Mage',
|
||||
};
|
||||
} else if (heroClass === 'healer') {
|
||||
return {
|
||||
armor: 'armor_healer_5',
|
||||
head: 'head_healer_5',
|
||||
shield: 'shield_healer_5',
|
||||
weapon: 'weapon_healer_6',
|
||||
armor: 'armor_special_winter2019Healer',
|
||||
head: 'head_special_winter2019Healer',
|
||||
shield: 'shield_special_winter2019Healer',
|
||||
weapon: 'weapon_special_winter2019Healer',
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
armor: 'armor_warrior_5',
|
||||
head: 'head_warrior_5',
|
||||
shield: 'shield_warrior_5',
|
||||
weapon: 'weapon_warrior_6',
|
||||
armor: 'armor_special_winter2019Warrior',
|
||||
head: 'head_special_winter2019Warrior',
|
||||
shield: 'shield_special_winter2019Warrior',
|
||||
weapon: 'weapon_special_winter2019Warrior',
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
.quest(:class='`quest_${user.party.quest.completed}`')
|
||||
p(v-if='questData.completion && typeof questData.completion === "function"', v-html='questData.completion()')
|
||||
.quest-rewards.text-center
|
||||
h3 {{ $t('youReceived') }}
|
||||
h3(v-once) {{ $t('paymentYouReceived') }}
|
||||
questDialogDrops(:item="questData")
|
||||
.modal-footer
|
||||
button.btn.btn-primary(@click='setQuestCompleted()') {{ $t('ok') }}
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
hr
|
||||
.row
|
||||
.col-12.col-md-5
|
||||
| © 2018 Habitica. All rights reserved.
|
||||
| © 2019 Habitica. All rights reserved.
|
||||
.debug.float-left(v-if="!IS_PRODUCTION && isUserLoaded")
|
||||
button.btn.btn-primary(@click="debugMenuShown = !debugMenuShown") Toggle Debug Menu
|
||||
.debug-group(v-if="debugMenuShown")
|
||||
@@ -96,6 +96,7 @@
|
||||
a.btn.btn-secondary(@click="plusTenHealth()") + 10HP
|
||||
a.btn.btn-secondary(@click="addMana()") +MP
|
||||
a.btn.btn-secondary(@click="addLevelsAndGold()") +Exp +GP +MP
|
||||
a.btn.btn-secondary(@click="addExp()") +Exp
|
||||
a.btn.btn-secondary(@click="addOneLevel()") +1 Level
|
||||
a.btn.btn-secondary(@click="addQuestProgress()", tooltip="+1000 to boss quests. 300 items to collection quests") Quest Progress Up
|
||||
a.btn.btn-secondary(@click="makeAdmin()") Make Admin
|
||||
@@ -326,7 +327,7 @@ export default {
|
||||
'stats.mp': this.user.stats.mp + 10000,
|
||||
});
|
||||
},
|
||||
addOneLevel () {
|
||||
addExp () {
|
||||
// @TODO: Name these variables better
|
||||
let exp = 0;
|
||||
let five = 10 * this.user.stats.lvl;
|
||||
@@ -340,6 +341,11 @@ export default {
|
||||
'stats.exp': exp,
|
||||
});
|
||||
},
|
||||
addOneLevel () {
|
||||
this.$store.dispatch('user:set', {
|
||||
'stats.lvl': this.user.stats.lvl + 1,
|
||||
});
|
||||
},
|
||||
async addQuestProgress () {
|
||||
await axios.post('/api/v4/debug/quest-progress');
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ b-modal#avatar-modal(title="", :size='editing ? "lg" : "md"', :hide-header='true
|
||||
.menu-item
|
||||
.svg-icon(v-html='icons.accessoriesIcon')
|
||||
strong(v-once) {{$t('extra')}}
|
||||
.menu-container.col-2(@click='changeTopPage("backgrounds", "2018")', v-if='editing', :class='{active: activeTopPage === "backgrounds"}')
|
||||
.menu-container.col-2(@click='changeTopPage("backgrounds", "2019")', v-if='editing', :class='{active: activeTopPage === "backgrounds"}')
|
||||
.menu-item
|
||||
.svg-icon(v-html='icons.backgroundsIcon')
|
||||
strong(v-once) {{$t('backgrounds')}}
|
||||
@@ -274,9 +274,11 @@ b-modal#avatar-modal(title="", :size='editing ? "lg" : "md"', :hide-header='true
|
||||
.incentive-background(:class='[`background_${bg.key}`]')
|
||||
.small-rectangle
|
||||
.row.sub-menu.col-10.offset-1(v-if='!filterBackgrounds')
|
||||
.col-3.text-center.sub-menu-item(@click='changeSubPage("2018")', :class='{active: activeSubPage === "2018"}')
|
||||
.col-2.text-center.sub-menu-item(@click='changeSubPage("2019")', :class='{active: activeSubPage === "2019"}')
|
||||
strong(v-once) 2019
|
||||
.col-2.text-center.sub-menu-item(@click='changeSubPage("2018")', :class='{active: activeSubPage === "2018"}')
|
||||
strong(v-once) 2018
|
||||
.col-3.text-center.sub-menu-item(@click='changeSubPage("2017")', :class='{active: activeSubPage === "2017"}')
|
||||
.col-2.text-center.sub-menu-item(@click='changeSubPage("2017")', :class='{active: activeSubPage === "2017"}')
|
||||
strong(v-once) 2017
|
||||
.col-2.text-center.sub-menu-item(@click='changeSubPage("2016")', :class='{active: activeSubPage === "2016"}')
|
||||
strong(v-once) 2016
|
||||
@@ -1297,6 +1299,7 @@ export default {
|
||||
2016: [],
|
||||
2017: [],
|
||||
2018: [],
|
||||
2019: [],
|
||||
};
|
||||
|
||||
// Hack to force update for now until we restructure the data
|
||||
|
||||
@@ -141,7 +141,7 @@ export default {
|
||||
this.changePage(this.PAGES.PAY);
|
||||
},
|
||||
pay (paymentMethod) {
|
||||
const subscriptionKey = 'group_monthly'; // @TODO: Get from content API?
|
||||
const subscriptionKey = 'group_monthly';
|
||||
let paymentData = {
|
||||
subscription: subscriptionKey,
|
||||
coupon: null,
|
||||
@@ -149,6 +149,7 @@ export default {
|
||||
|
||||
if (this.upgradingGroup && this.upgradingGroup._id) {
|
||||
paymentData.groupId = this.upgradingGroup._id;
|
||||
paymentData.group = this.upgradingGroup;
|
||||
} else {
|
||||
paymentData.groupToCreate = this.newGroup;
|
||||
}
|
||||
|
||||
@@ -395,14 +395,15 @@ export default {
|
||||
this.changePage(this.PAGES.PAY);
|
||||
},
|
||||
pay (paymentMethod) {
|
||||
let subscriptionKey = 'group_monthly'; // @TODO: Get from content API?
|
||||
let paymentData = {
|
||||
const subscriptionKey = 'group_monthly'; // @TODO: Get from content API?
|
||||
const paymentData = {
|
||||
subscription: subscriptionKey,
|
||||
coupon: null,
|
||||
};
|
||||
|
||||
if (this.upgradingGroup && this.upgradingGroup._id) {
|
||||
paymentData.groupId = this.upgradingGroup._id;
|
||||
paymentData.group = this.upgradingGroup;
|
||||
} else {
|
||||
paymentData.groupToCreate = this.newGroup;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ menu-dropdown.item-user(:right="true")
|
||||
a.nav-link.dropdown-item.dropdown-separated.d-flex.justify-content-between.align-items-center(@click.prevent='showInbox()')
|
||||
div {{ $t('messages') }}
|
||||
message-count(v-if='user.inbox.newMessages > 0', :count="user.inbox.newMessages")
|
||||
a.dropdown-item(@click='showAvatar("backgrounds", "2018")') {{ $t('backgrounds') }}
|
||||
a.dropdown-item(@click='showAvatar("backgrounds", "2019")') {{ $t('backgrounds') }}
|
||||
a.dropdown-item(@click='showProfile("stats")') {{ $t('stats') }}
|
||||
a.dropdown-item(@click='showProfile("achievements")') {{ $t('achievements') }}
|
||||
a.dropdown-item.dropdown-separated(@click='showProfile("profile")') {{ $t('profile') }}
|
||||
|
||||
@@ -6,7 +6,7 @@ b-modal#hatchedPet-modal(:hide-header="true")
|
||||
div.pet-background
|
||||
div(:class="pet.class")
|
||||
h4.title {{ pet.name }}
|
||||
div.text(v-if="!hideText", v-markdown="$t('hatchedPetHowToUse')")
|
||||
div.text(v-if="!hideText", v-markdown="$t('hatchedPetHowToUse', { stableUrl: '/inventory/stable' })")
|
||||
button.btn.btn-primary(@click="close()") {{ $t('onward') }}
|
||||
div.clearfix(slot="modal-footer")
|
||||
</template>
|
||||
|
||||
@@ -569,10 +569,8 @@ export default {
|
||||
break;
|
||||
case 'STREAK_ACHIEVEMENT':
|
||||
this.text(`${this.$t('streaks')}: ${this.user.achievements.streak}`, () => {
|
||||
if (!this.user.preferences.suppressModals.streak) {
|
||||
this.$root.$emit('bv::show::modal', 'streak');
|
||||
}
|
||||
});
|
||||
this.$root.$emit('bv::show::modal', 'streak');
|
||||
}, this.user.preferences.suppressModals.streak);
|
||||
this.playSound('Achievement_Unlocked');
|
||||
break;
|
||||
case 'ULTIMATE_GEAR_ACHIEVEMENT':
|
||||
|
||||
@@ -34,6 +34,7 @@ import * as Analytics from 'client/libs/analytics';
|
||||
import axios from 'axios';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import { CONSTANTS, setLocalSetting } from 'client/libs/userlocalManager';
|
||||
import pick from 'lodash/pick';
|
||||
|
||||
const AMAZON_PAYMENTS = process.env.AMAZON_PAYMENTS; // eslint-disable-line
|
||||
const habiticaUrl = `${location.protocol}//${location.host}`;
|
||||
@@ -56,6 +57,8 @@ export default {
|
||||
OffAmazonPayments: {},
|
||||
isAmazonSetup: false,
|
||||
amazonButtonEnabled: false,
|
||||
groupToCreate: null, // creating new group
|
||||
group: null, // upgrading existing group
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -189,10 +192,37 @@ export default {
|
||||
new this.OffAmazonPayments.Widgets.Wallet(walletParams).bind('AmazonPayWallet');
|
||||
},
|
||||
storePaymentStatusAndReload (url) {
|
||||
let paymentType;
|
||||
|
||||
if (this.amazonPayments.type === 'single' && !this.amazonPayments.gift) paymentType = 'gems';
|
||||
if (this.amazonPayments.type === 'subscription') paymentType = 'subscription';
|
||||
if (this.amazonPayments.groupId || this.amazonPayments.groupToCreate) paymentType = 'groupPlan';
|
||||
if (this.amazonPayments.type === 'single' && this.amazonPayments.gift && this.amazonPayments.giftReceiver) {
|
||||
paymentType = this.amazonPayments.gift.type === 'gems' ? 'gift-gems' : 'gift-subscription';
|
||||
}
|
||||
|
||||
const appState = {
|
||||
paymentMethod: 'amazon',
|
||||
paymentCompleted: true,
|
||||
paymentType,
|
||||
};
|
||||
if (paymentType === 'subscription') {
|
||||
appState.subscriptionKey = this.amazonPayments.subscription;
|
||||
} else if (paymentType === 'groupPlan') {
|
||||
appState.subscriptionKey = this.amazonPayments.subscription;
|
||||
|
||||
if (this.amazonPayments.groupToCreate) {
|
||||
appState.newGroup = true;
|
||||
appState.group = pick(this.amazonPayments.groupToCreate, ['_id', 'memberCount', 'name']);
|
||||
} else {
|
||||
appState.newGroup = false;
|
||||
appState.group = pick(this.amazonPayments.group, ['_id', 'memberCount', 'name']);
|
||||
}
|
||||
} else if (paymentType.indexOf('gift-') === 0) {
|
||||
appState.gift = this.amazonPayments.gift;
|
||||
appState.giftReceiver = this.amazonPayments.giftReceiver;
|
||||
}
|
||||
|
||||
setLocalSetting(CONSTANTS.savedAppStateValues.SAVED_APP_STATE, JSON.stringify(appState));
|
||||
if (url) {
|
||||
window.location.assign(url);
|
||||
@@ -215,11 +245,11 @@ export default {
|
||||
});
|
||||
|
||||
this.$set(this, 'amazonButtonEnabled', true);
|
||||
this.reset();
|
||||
this.storePaymentStatusAndReload();
|
||||
} catch (e) {
|
||||
console.error(e); // eslint-disable-line no-console
|
||||
this.$set(this, 'amazonButtonEnabled', true);
|
||||
this.amazonPaymentsreset();
|
||||
this.reset();
|
||||
}
|
||||
} else if (this.amazonPayments.type === 'subscription') {
|
||||
let url = '/amazon/subscribe';
|
||||
@@ -265,7 +295,6 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
this.reset();
|
||||
this.storePaymentStatusAndReload();
|
||||
} catch (e) {
|
||||
this.$set(this, 'amazonButtonEnabled', true);
|
||||
@@ -286,13 +315,19 @@ export default {
|
||||
this.amazonPayments.modal = null;
|
||||
this.amazonPayments.type = null;
|
||||
this.amazonPayments.loggedIn = false;
|
||||
|
||||
// Gift
|
||||
this.amazonPayments.gift = null;
|
||||
this.amazonPayments.giftReceiver = null;
|
||||
|
||||
this.amazonPayments.billingAgreementId = null;
|
||||
this.amazonPayments.orderReferenceId = null;
|
||||
this.amazonPayments.paymentSelected = false;
|
||||
this.amazonPayments.recurringConsent = false;
|
||||
this.amazonPayments.subscription = null;
|
||||
this.amazonPayments.coupon = null;
|
||||
this.amazonPayments.groupToCreate = null;
|
||||
this.amazonPayments.group = null;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -2,180 +2,172 @@
|
||||
mixin featureBullet (text)
|
||||
.row
|
||||
.col-md-2.offset-1
|
||||
.bubble.mx-auto
|
||||
.svg-icon.check(v-html='icons.check')
|
||||
.d-flex.bubble.justify-content-center.align-items-center
|
||||
.svg-icon.check.mx-auto(v-html='icons.check')
|
||||
.col-md-8.align-self-center
|
||||
p=text
|
||||
div(v-if='user')
|
||||
b-modal(:hide-footer='true', :hide-header='true', :id='"buy-gems"', size='lg')
|
||||
.container-fluid.purple-gradient
|
||||
.gemfall
|
||||
b-modal#buy-gems(:hide-footer='true', size='lg')
|
||||
.header-wrap(slot='modal-header')
|
||||
.image-gemfall
|
||||
.row
|
||||
h2.text-invert.mx-auto {{ $t('support') }}
|
||||
h2.header-invert.mx-auto {{ $t('support') }}
|
||||
.row
|
||||
.logo.svg-icon.mx-auto(v-html="icons.logo")
|
||||
.container-fluid
|
||||
.row
|
||||
.col-6.offset-3.nav
|
||||
.nav-item(@click='selectedPage = "subscribe"', :class="{active: selectedPage === 'subscribe'}") {{ $t('subscribe') }}
|
||||
.nav-item(@click='selectedPage = "gems"', :class="{active: selectedPage === 'gems'}") {{ $t('buyGems') }}
|
||||
div(v-show='selectedPage === "gems"')
|
||||
div(v-if='hasSubscription')
|
||||
.row.text-center
|
||||
h2.mx-auto.text-leadin {{ $t('subscriptionAlreadySubscribedLeadIn') }}
|
||||
.row.text-center
|
||||
.col-6.offset-3
|
||||
p {{ $t("gemsPurchaseNote") }}
|
||||
.d-flex.nav.justify-content-center
|
||||
.nav-item.text-center(@click='selectedPage = "subscribe"', :class="{active: selectedPage === 'subscribe'}") {{ $t('subscribe') }}
|
||||
.nav-item.text-center(@click='selectedPage = "gems"', :class="{active: selectedPage === 'gems'}") {{ $t('buyGems') }}
|
||||
div(v-show='selectedPage === "gems"')
|
||||
div(v-if='hasSubscription')
|
||||
.row.text-center
|
||||
h2.mx-auto.text-leadin {{ $t('gemBenefitLeadin') }}
|
||||
h2.mx-auto.text-leadin {{ $t('subscriptionAlreadySubscribedLeadIn') }}
|
||||
.row.text-center
|
||||
.col-6.offset-3
|
||||
p {{ $t("gemsPurchaseNote") }}
|
||||
.row.text-center
|
||||
h2.mx-auto.text-leadin {{ $t('gemBenefitLeadin') }}
|
||||
.row
|
||||
.col
|
||||
+featureBullet("{{ $t('gemBenefit1') }}")
|
||||
+featureBullet("{{ $t('gemBenefit2') }}")
|
||||
.col
|
||||
+featureBullet("{{ $t('gemBenefit3') }}")
|
||||
+featureBullet("{{ $t('gemBenefit4') }}")
|
||||
.card-deck.gem-deck
|
||||
.card.text-center.col-3(:class="{active: gemAmount === 20 }")
|
||||
.card-img-top
|
||||
.mx-auto(v-html='icons.twentyOneGems', style='"height: 55px; width: 47.5px; margin-top: 1.85em;"')
|
||||
.card-body
|
||||
.gem-count 20
|
||||
.gem-text {{ $t('gems') }}
|
||||
.divider
|
||||
button.btn.btn-primary(@click='gemAmount === 20 ? gemAmount = 0 : gemAmount = 20') {{gemAmount === 20 ? $t('selected') : '$5.00'}}
|
||||
.row.text-center
|
||||
h2.mx-auto.text-payment {{ $t('choosePaymentMethod') }}
|
||||
.card-deck
|
||||
.card.text-center.payment-method(@click='showStripe({})')
|
||||
.card-body
|
||||
.mx-auto(v-html='icons.creditCard', style='"height: 56px; width: 159px; margin-top: 1em;"')
|
||||
.card.text-center.payment-method
|
||||
a.card-body.paypal(@click="openPaypal(paypalCheckoutLink, 'gems')")
|
||||
img(src='~assets/images/paypal.png')
|
||||
.card.text-center.payment-method(@click="amazonPaymentsInit({type: 'single'})")
|
||||
.card-body.amazon
|
||||
img(src='~assets/images/amazon-payments.png')
|
||||
.row.text-center
|
||||
.svg-icon.mx-auto(v-html='icons.heart', style='"height: 24px; width: 24px;"')
|
||||
.row.text-center.text-outtro
|
||||
.col-6.offset-3 {{ $t('buyGemsSupportsDevs') }}
|
||||
|
||||
div(v-show='selectedPage === "subscribe"')
|
||||
.g1g1-promo.d-flex.justify-content-center.align-items-center
|
||||
.svg-icon.svg-gifts.left-gift(v-html="icons.gifts")
|
||||
.text-center
|
||||
strong.gift-text {{ $t('g1g1Announcement') }}
|
||||
.gift-text {{ $t('g1g1Details') }}
|
||||
.svg-icon.svg-gifts.right-gift(v-html="icons.gifts")
|
||||
div(v-if='hasSubscription')
|
||||
.row.text-center
|
||||
h2.mx-auto.text-leadin {{ $t('subscriptionAlreadySubscribedLeadIn') }}
|
||||
.row.text-center
|
||||
.col-10.offset-1
|
||||
p(v-html='$t("subscriptionAlreadySubscribed1")')
|
||||
div(v-if='!hasSubscription')
|
||||
.row.text-center
|
||||
h2.mx-auto.text-leadin {{ $t('subscriptionBenefitLeadin') }}
|
||||
.row
|
||||
.col
|
||||
+featureBullet("{{ $t('gemBenefit1') }}")
|
||||
+featureBullet("{{ $t('gemBenefit2') }}")
|
||||
+featureBullet("{{ $t('subscriptionBenefit1') }}")
|
||||
+featureBullet("{{ $t('subscriptionBenefit2') }}")
|
||||
+featureBullet("{{ $t('subscriptionBenefit3') }}")
|
||||
.col
|
||||
+featureBullet("{{ $t('gemBenefit3') }}")
|
||||
+featureBullet("{{ $t('gemBenefit4') }}")
|
||||
.card-deck.gem-deck
|
||||
//.card.text-center(:class="{active: gemAmount === 4}")
|
||||
.card-img-top
|
||||
.mx-auto(v-html='icons.fourGems', style='"height: 53px; width: 49.5px; margin-top: 2em;"')
|
||||
.card-body
|
||||
.gem-count 4
|
||||
.gem-text {{ $t('gems') }}
|
||||
.divider
|
||||
button.btn.btn-primary(@click='gemAmount = 4') {{gemAmount === 4 ? $t('selected') : '$1.00'}}
|
||||
.card.text-center.col-3(:class="{active: gemAmount === 20 }")
|
||||
.card-img-top
|
||||
.mx-auto(v-html='icons.twentyOneGems', style='"height: 55px; width: 47.5px; margin-top: 1.85em;"')
|
||||
.card-body
|
||||
.gem-count 20
|
||||
.gem-text {{ $t('gems') }}
|
||||
.divider
|
||||
button.btn.btn-primary(@click='gemAmount === 20 ? gemAmount = 0 : gemAmount = 20') {{gemAmount === 20 ? $t('selected') : '$5.00'}}
|
||||
//.card.text-center(:class="{active: gemAmount === 42}")
|
||||
.card-img-top
|
||||
.mx-auto(v-html='icons.fortyTwoGems', style='"height: 49.5px; width: 51px; margin-top: 1.9em;"')
|
||||
.card-body
|
||||
.gem-count 42
|
||||
.gem-text {{ $t('gems') }}
|
||||
.divider
|
||||
button.btn.btn-primary(@click='gemAmount = 42') {{gemAmount === 42 ? $t('selected') : '$10.00'}}
|
||||
//.card.text-center(:class="{active: gemAmount === 84}")
|
||||
.card-img-top
|
||||
.mx-auto(v-html='icons.eightyFourGems', style='"height: 65px; width: 67px; margin-top: 1em;"')
|
||||
.card-body
|
||||
.gem-count 84
|
||||
.gem-text {{ $t('gems') }}
|
||||
.divider
|
||||
button.btn.btn-primary(@click='gemAmount = 84') {{gemAmount === 84 ? $t('selected') : '$20.00'}}
|
||||
.row.text-center
|
||||
h2.mx-auto.text-payment {{ $t('choosePaymentMethod') }}
|
||||
+featureBullet("{{ $t('subscriptionBenefit4') }}")
|
||||
+featureBullet("{{ $t('subscriptionBenefit5') }}")
|
||||
+featureBullet("{{ $t('subscriptionBenefit6') }}")
|
||||
.card-deck
|
||||
.card.text-center.payment-method(@click='showStripe({})')
|
||||
.card.text-center(:class='{active: subscriptionPlan === "basic_earned"}')
|
||||
.card-body
|
||||
.subscription-price
|
||||
span.superscript $
|
||||
span 5
|
||||
span.superscript.muted .00
|
||||
.small(v-once) {{ $t('everyMonth') }}
|
||||
.divider
|
||||
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:25})')
|
||||
.spacer
|
||||
button.btn.btn-primary(@click='subscriptionPlan = "basic_earned"') {{ subscriptionPlan === "basic_earned" ? $t('selected') : $t('select') }}
|
||||
.card.text-center(:class='{active: subscriptionPlan === "basic_3mo"}')
|
||||
.card-body
|
||||
.subscription-price
|
||||
span.superscript $
|
||||
span 15
|
||||
span.superscript.muted .00
|
||||
.small(v-once) {{ $t('everyXMonths', {interval: 3}) }}
|
||||
.divider
|
||||
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:30})')
|
||||
p.benefits(v-markdown='$t("receiveMysticHourglass")')
|
||||
button.btn.btn-primary(@click='subscriptionPlan = "basic_3mo"') {{ subscriptionPlan === "basic_3mo" ? $t('selected') : $t('select') }}
|
||||
.card.text-center(:class='{active: subscriptionPlan === "basic_6mo"}')
|
||||
.card-body
|
||||
.subscription-price
|
||||
span.superscript $
|
||||
span 30
|
||||
span.superscript.muted .00
|
||||
.small(v-once) {{ $t('everyXMonths', {interval: 6}) }}
|
||||
.divider
|
||||
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:35})')
|
||||
p.benefits(v-markdown='$t("receiveMysticHourglasses", {amount:2})')
|
||||
button.btn.btn-primary(@click='subscriptionPlan = "basic_6mo"') {{ subscriptionPlan === "basic_6mo" ? $t('selected') : $t('select') }}
|
||||
.card.text-center(:class='{active: subscriptionPlan === "basic_12mo"}')
|
||||
.card-body
|
||||
.subscription-price
|
||||
span.superscript $
|
||||
span 48
|
||||
span.superscript.muted .00
|
||||
.small(v-once) {{ $t('everyYear') }}
|
||||
.divider
|
||||
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:45})')
|
||||
p.benefits(v-markdown='$t("receiveMysticHourglasses", {amount:4})')
|
||||
button.btn.btn-primary(@click='subscriptionPlan = "basic_12mo"') {{ subscriptionPlan === "basic_12mo" ? $t('selected') : $t('select') }}
|
||||
.row.text-center(v-if='subscriptionPlan')
|
||||
h2.mx-auto.text-payment(v-once) {{ $t('choosePaymentMethod') }}
|
||||
.row.text-center
|
||||
a.mx-auto(v-once) {{ $t('haveCouponCode') }}
|
||||
.card-deck(v-if='subscriptionPlan')
|
||||
.card.text-center.payment-method
|
||||
.card-body(@click='showStripe({subscription: subscriptionPlan})')
|
||||
.mx-auto(v-html='icons.creditCard', style='"height: 56px; width: 159px; margin-top: 1em;"')
|
||||
.card.text-center.payment-method
|
||||
a.card-body.paypal(@click="openPaypal(paypalCheckoutLink, 'gems')")
|
||||
a.card-body.paypal(@click="openPaypal(paypalSubscriptionLink, 'subscription')")
|
||||
img(src='~assets/images/paypal.png')
|
||||
.card.text-center.payment-method(@click="amazonPaymentsInit({type: 'single'})")
|
||||
.card-body.amazon
|
||||
.card.text-center.payment-method
|
||||
.card-body.amazon(@click="amazonPaymentsInit({type: 'subscription', subscription: subscriptionPlan})")
|
||||
img(src='~assets/images/amazon-payments.png')
|
||||
.row.text-center
|
||||
.svg-icon.mx-auto(v-html='icons.heart', style='"height: 24px; width: 24px;"')
|
||||
.row.text-center.text-outtro
|
||||
.col-6.offset-3 {{ $t('buyGemsSupportsDevs') }}
|
||||
|
||||
div(v-show='selectedPage === "subscribe"')
|
||||
div(v-if='hasSubscription')
|
||||
.row.text-center
|
||||
h2.mx-auto.text-leadin {{ $t('subscriptionAlreadySubscribedLeadIn') }}
|
||||
.row.text-center
|
||||
.col
|
||||
p(v-html='$t("subscriptionAlreadySubscribed1")')
|
||||
div(v-if='!hasSubscription')
|
||||
.row.text-center
|
||||
h2.mx-auto.text-leadin {{ $t('subscriptionBenefitLeadin') }}
|
||||
.row
|
||||
.col
|
||||
+featureBullet("{{ $t('subscriptionBenefit1') }}")
|
||||
+featureBullet("{{ $t('subscriptionBenefit2') }}")
|
||||
+featureBullet("{{ $t('subscriptionBenefit3') }}")
|
||||
.col
|
||||
+featureBullet("{{ $t('subscriptionBenefit4') }}")
|
||||
+featureBullet("{{ $t('subscriptionBenefit5') }}")
|
||||
+featureBullet("{{ $t('subscriptionBenefit6') }}")
|
||||
.card-deck
|
||||
.card.text-center(:class='{active: subscriptionPlan === "basic_earned"}')
|
||||
.card-body
|
||||
.subscription-price
|
||||
span.superscript $
|
||||
span 5
|
||||
span.superscript.muted .00
|
||||
.small {{ $t('everyMonth') }}
|
||||
.divider
|
||||
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:25})')
|
||||
.spacer
|
||||
button.btn.btn-primary(@click='subscriptionPlan = "basic_earned"') {{ subscriptionPlan === "basic_earned" ? $t('selected') : $t('select') }}
|
||||
.card.text-center(:class='{active: subscriptionPlan === "basic_3mo"}')
|
||||
.card-body
|
||||
.subscription-price
|
||||
span.superscript $
|
||||
span 15
|
||||
span.superscript.muted .00
|
||||
.small {{ $t('everyXMonths', {interval: 3}) }}
|
||||
.divider
|
||||
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:30})')
|
||||
p.benefits(v-markdown='$t("receiveMysticHourglass")')
|
||||
button.btn.btn-primary(@click='subscriptionPlan = "basic_3mo"') {{ subscriptionPlan === "basic_3mo" ? $t('selected') : $t('select') }}
|
||||
.card.text-center(:class='{active: subscriptionPlan === "basic_6mo"}')
|
||||
.card-body
|
||||
.subscription-price
|
||||
span.superscript $
|
||||
span 30
|
||||
span.superscript.muted .00
|
||||
.small {{ $t('everyXMonths', {interval: 6}) }}
|
||||
.divider
|
||||
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:35})')
|
||||
p.benefits(v-markdown='$t("receiveMysticHourglasses", {amount:2})')
|
||||
button.btn.btn-primary(@click='subscriptionPlan = "basic_6mo"') {{ subscriptionPlan === "basic_6mo" ? $t('selected') : $t('select') }}
|
||||
.card.text-center(:class='{active: subscriptionPlan === "basic_12mo"}')
|
||||
.card-body
|
||||
.subscription-price
|
||||
span.superscript $
|
||||
span 48
|
||||
span.superscript.muted .00
|
||||
.small {{ $t('everyYear') }}
|
||||
.divider
|
||||
p.benefits(v-markdown='$t("earnGemsMonthly", {cap:45})')
|
||||
p.benefits(v-markdown='$t("receiveMysticHourglasses", {amount:4})')
|
||||
button.btn.btn-primary(@click='subscriptionPlan = "basic_12mo"') {{ subscriptionPlan === "basic_12mo" ? $t('selected') : $t('select') }}
|
||||
.row.text-center(v-if='subscriptionPlan')
|
||||
h2.mx-auto.text-payment {{ $t('choosePaymentMethod') }}
|
||||
.row.text-center
|
||||
a.mx-auto {{ $t('haveCouponCode') }}
|
||||
.card-deck(v-if='subscriptionPlan')
|
||||
.card.text-center.payment-method
|
||||
.card-body(@click='showStripe({subscription: subscriptionPlan})')
|
||||
.mx-auto(v-html='icons.creditCard', style='"height: 56px; width: 159px; margin-top: 1em;"')
|
||||
.card.text-center.payment-method
|
||||
a.card-body.paypal(@click="openPaypal(paypalSubscriptionLink, 'subscription')")
|
||||
img(src='~assets/images/paypal.png')
|
||||
.card.text-center.payment-method
|
||||
.card-body.amazon(@click="amazonPaymentsInit({type: 'subscription', subscription: subscriptionPlan})")
|
||||
img(src='~assets/images/amazon-payments.png')
|
||||
.row.text-center
|
||||
.svg-icon.mx-auto(v-html='icons.heart', style='"height: 24px; width: 24px;"')
|
||||
.row.text-center.text-outtro
|
||||
.col-6.offset-3 {{ $t('subscribeSupportsDevs') }}
|
||||
.col-6.offset-3 {{ $t('subscribeSupportsDevs') }}
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
#buy-gems__BV_body_ {
|
||||
#buy-gems .modal-body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#buy-gems .modal-content {
|
||||
border-radius: 8px;
|
||||
width: 824px;
|
||||
}
|
||||
|
||||
#buy-gems .modal-header {
|
||||
padding: 0;
|
||||
border-bottom: 0px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
a.mx-auto {
|
||||
color: #2995cd;
|
||||
}
|
||||
@@ -228,6 +220,11 @@
|
||||
margin: 1em auto;
|
||||
}
|
||||
|
||||
.g1g1-promo {
|
||||
background-color: #34b5c1;
|
||||
height: 3.75rem;
|
||||
}
|
||||
|
||||
.gem-count {
|
||||
font-family: Roboto;
|
||||
font-size: 40px;
|
||||
@@ -242,11 +239,40 @@
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.gemfall {
|
||||
.gift-text {
|
||||
color: $white;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.image-gemfall {
|
||||
background: url(~assets/images/gemfall.png) center repeat-y;
|
||||
height: 14em;
|
||||
}
|
||||
|
||||
.svg-gifts {
|
||||
width: 4.6rem;
|
||||
}
|
||||
|
||||
.left-gift {
|
||||
margin: auto 1rem auto 4.8rem;
|
||||
}
|
||||
|
||||
.right-gift {
|
||||
margin: auto 4.8rem auto 1rem;
|
||||
filter: FlipH;
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.header-wrap {
|
||||
background-image: linear-gradient(74deg, #4f2a93, #6133b4);
|
||||
height: 14em;
|
||||
width: 100%;
|
||||
color: #4e4a57;
|
||||
padding: 0;
|
||||
border-top-left-radius: 7px;
|
||||
border-top-right-radius: 7px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 256px;
|
||||
height: 56px;
|
||||
@@ -258,19 +284,21 @@
|
||||
|
||||
.nav {
|
||||
font-weight: bold;
|
||||
height: 40px;
|
||||
background-color: $gray-600;
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
margin: 0 auto;
|
||||
padding: 1.5em;
|
||||
margin: 0rem;
|
||||
padding: 1rem;
|
||||
width: 7.5rem;
|
||||
}
|
||||
|
||||
.nav-item:hover, .nav-item.active {
|
||||
color: #4f2a93;
|
||||
border-bottom: 2px solid #4f2a93;
|
||||
border-bottom: 4px solid $purple-300;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -286,11 +314,6 @@
|
||||
padding-top: 1.3em;
|
||||
}
|
||||
|
||||
.purple-gradient {
|
||||
background-image: linear-gradient(74deg, #4f2a93, #6133b4);
|
||||
height: 14em;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
height: 4em;
|
||||
}
|
||||
@@ -309,10 +332,11 @@
|
||||
|
||||
.svg-icon.check {
|
||||
color: #bda8ff;
|
||||
width: 1rem;
|
||||
}
|
||||
|
||||
.text-invert {
|
||||
margin: 1.6em;
|
||||
.header-invert {
|
||||
margin: 3rem auto 1.5rem;
|
||||
color: #FFFFFF;
|
||||
font-family: Roboto;
|
||||
font-weight: normal;
|
||||
@@ -320,9 +344,9 @@
|
||||
}
|
||||
|
||||
.text-leadin {
|
||||
margin: 1.6em;
|
||||
font-weight: normal;
|
||||
color: #4f2a93;
|
||||
margin: 1rem;
|
||||
font-weight: bold;
|
||||
color: $purple-200;
|
||||
}
|
||||
|
||||
.text-outtro {
|
||||
@@ -346,6 +370,7 @@
|
||||
|
||||
import checkIcon from 'assets/svg/check.svg';
|
||||
import creditCard from 'assets/svg/credit-card.svg';
|
||||
import gifts from 'assets/svg/gifts.svg';
|
||||
import heart from 'assets/svg/health.svg';
|
||||
import logo from 'assets/svg/habitica-logo.svg';
|
||||
|
||||
@@ -381,6 +406,7 @@
|
||||
check: checkIcon,
|
||||
creditCard,
|
||||
fourGems,
|
||||
gifts,
|
||||
heart,
|
||||
twentyOneGems,
|
||||
fortyTwoGems,
|
||||
|
||||
@@ -31,11 +31,17 @@ b-modal#send-gems(:title="title", :hide-footer="true", size='lg', @hide='onHide(
|
||||
)
|
||||
h3.panel-heading {{ $t('subscription') }}
|
||||
.panel-body
|
||||
.form-group
|
||||
.radio(v-for='block in subscriptionBlocks', v-if="block.target !== 'group' && block.canSubscribe === true")
|
||||
label
|
||||
input(type="radio", name="subRadio", :value="block.key", v-model='gift.subscription.key')
|
||||
| {{ $t('sendGiftSubscription', {price: block.price, months: block.months}) }}
|
||||
.row
|
||||
.col-md-4
|
||||
.form-group
|
||||
.radio(v-for='block in subscriptionBlocks', v-if="block.target !== 'group' && block.canSubscribe === true")
|
||||
label
|
||||
input(type="radio", name="subRadio", :value="block.key", v-model='gift.subscription.key')
|
||||
| {{ $t('sendGiftSubscription', {price: block.price, months: block.months}) }}
|
||||
.col-md-8
|
||||
h4 {{ $t('winterPromoGiftHeader') }}
|
||||
p {{ $t('winterPromoGiftDetails1') }}
|
||||
p {{ $t('winterPromoGiftDetails2') }}
|
||||
|
||||
textarea.form-control(rows='3', v-model='gift.message', :placeholder="$t('sendGiftMessagePlaceholder')")
|
||||
//include ../formatting-help
|
||||
@@ -47,9 +53,9 @@ b-modal#send-gems(:title="title", :hide-footer="true", size='lg', @hide='onHide(
|
||||
:disabled="sendingInProgress"
|
||||
) {{ $t("send") }}
|
||||
template(v-else)
|
||||
button.btn.btn-primary(@click='showStripe({gift, uuid: userReceivingGems._id})') {{ $t('card') }}
|
||||
button.btn.btn-warning(@click='openPaypalGift({gift: gift, giftedTo: userReceivingGems._id})') PayPal
|
||||
button.btn.btn-success(@click="amazonPaymentsInit({type: 'single', gift, giftedTo: userReceivingGems._id})") Amazon Payments
|
||||
button.btn.btn-primary(@click='showStripe({gift, uuid: userReceivingGems._id, receiverName})') {{ $t('card') }}
|
||||
button.btn.btn-warning(@click='openPaypalGift({gift: gift, giftedTo: userReceivingGems._id, receiverName})') PayPal
|
||||
button.btn.btn-success(@click="amazonPaymentsInit({type: 'single', gift, giftedTo: userReceivingGems._id, receiverName})") Amazon Payments
|
||||
button.btn.btn-secondary(@click='close()') {{$t('cancel')}}
|
||||
</template>
|
||||
|
||||
@@ -131,6 +137,13 @@ export default {
|
||||
if (!this.userReceivingGems) return '';
|
||||
return this.$t('sendGiftHeading', {name: this.userReceivingGems.profile.name});
|
||||
},
|
||||
receiverName () {
|
||||
if (this.userReceivingGems.auth && this.userReceivingGems.auth.local && this.userReceivingGems.auth.local.username) {
|
||||
return this.userReceivingGems.auth.local.username;
|
||||
} else {
|
||||
return this.userReceivingGems.profile.name;
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// @TODO move to payments mixin or action (problem is that we need notifications)
|
||||
@@ -141,11 +154,23 @@ export default {
|
||||
toUserId: this.userReceivingGems._id,
|
||||
gemAmount: this.gift.gems.amount,
|
||||
});
|
||||
this.text(this.$t('sentGems'));
|
||||
this.close();
|
||||
setTimeout(() => { // wait for the send gem modal to be closed
|
||||
this.$root.$emit('habitica:payment-success', {
|
||||
paymentMethod: 'balance',
|
||||
paymentCompleted: true,
|
||||
paymentType: 'gift-gems-balance',
|
||||
gift: {
|
||||
gems: {
|
||||
amount: this.gift.gems.amount,
|
||||
},
|
||||
},
|
||||
giftReceiver: this.receiverName,
|
||||
});
|
||||
}, 500);
|
||||
},
|
||||
onHide () {
|
||||
// TODO this breaks amazon purchases because when the amazon modal
|
||||
// @TODO this breaks amazon purchases because when the amazon modal
|
||||
// is opened this one is closed and the amount reset
|
||||
// this.gift.gems.amount = 0;
|
||||
this.gift.message = '';
|
||||
|
||||
@@ -1,17 +1,39 @@
|
||||
<template lang="pug">
|
||||
b-modal#payments-success-modal(
|
||||
:title="$t('accountSuspendedTitle')",
|
||||
size='sm',
|
||||
size='sm',
|
||||
:hideFooter="isFromBalance",
|
||||
:modalClass="isFromBalance ? ['modal-hidden-footer'] : []"
|
||||
)
|
||||
div(slot="modal-header")
|
||||
.check-container.d-flex.align-items-center.justify-content-center
|
||||
.svg-icon.check(v-html="icons.check")
|
||||
h2(v-ocne) {{ $t('paymentSuccessful') }}
|
||||
.svg-icon.check(v-html="icons.check", v-once)
|
||||
h2 {{ $t(isFromBalance ? 'success' : 'paymentSuccessful') }}
|
||||
div(slot="modal-footer")
|
||||
.small-text(v-once) {{ $t('giftSubscriptionText4') }}
|
||||
.row
|
||||
.col-12.text-center
|
||||
button.btn.btn-primary(@click='close()') {{$t('onwards')}}
|
||||
.col-12.modal-body-col
|
||||
template(v-if="paymentData.paymentType === 'gems'")
|
||||
strong(v-once) {{ $t('paymentYouReceived') }}
|
||||
.details-block.gems
|
||||
.svg-icon(v-html="icons.gem", v-once)
|
||||
span 20
|
||||
template(v-if="paymentData.paymentType === 'gift-gems' || paymentData.paymentType === 'gift-gems-balance'")
|
||||
span(v-html="$t('paymentYouSentGems', {name: paymentData.giftReceiver})")
|
||||
.details-block.gems
|
||||
.svg-icon(v-html="icons.gem", v-once)
|
||||
span {{ paymentData.gift.gems.amount }}
|
||||
template(v-if="paymentData.paymentType === 'gift-subscription'")
|
||||
span(v-html="$t('paymentYouSentSubscription', {name: paymentData.giftReceiver, months: paymentData.subscription.months})")
|
||||
template(v-if="paymentData.paymentType === 'subscription'")
|
||||
strong(v-once) {{ $t('nowSubscribed') }}
|
||||
.details-block
|
||||
span(v-html="$t('paymentSubBilling', {amount: paymentData.subscription.price, months: paymentData.subscription.months})")
|
||||
template(v-if="paymentData.paymentType === 'groupPlan'")
|
||||
span(v-html="$t(paymentData.newGroup ? 'groupPlanCreated' : 'groupPlanUpgraded', {groupName: paymentData.group.name})")
|
||||
.details-block
|
||||
span(v-html="$t('paymentSubBilling', {amount: groupPlanCost, months: paymentData.subscription.months})")
|
||||
button.btn.btn-primary(@click='close()', v-once) {{$t('onwards')}}
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@@ -21,6 +43,11 @@
|
||||
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;
|
||||
@@ -28,6 +55,8 @@
|
||||
background: $green-10;
|
||||
border-top-right-radius: 8px;
|
||||
border-top-left-radius: 8px;
|
||||
border-bottom: none;
|
||||
|
||||
h2 {
|
||||
color: white;
|
||||
}
|
||||
@@ -52,6 +81,41 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#payments-success-modal .modal-footer {
|
||||
@@ -59,6 +123,7 @@
|
||||
border-bottom-right-radius: 8px;
|
||||
border-bottom-left-radius: 8px;
|
||||
justify-content: center;
|
||||
border-top: none;
|
||||
|
||||
.small-text {
|
||||
font-style: normal;
|
||||
@@ -68,17 +133,45 @@
|
||||
|
||||
<script>
|
||||
import checkIcon from 'assets/svg/check.svg';
|
||||
import gemIcon from 'assets/svg/gem.svg';
|
||||
import subscriptionBlocks from '../../../common/script/content/subscriptionBlocks';
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
check: checkIcon,
|
||||
gem: gemIcon,
|
||||
}),
|
||||
paymentData: {},
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
this.$root.$on('habitica:payment-success', (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');
|
||||
});
|
||||
},
|
||||
destroyed () {
|
||||
this.paymentData = {};
|
||||
this.$root.$off('habitica:payments-success');
|
||||
},
|
||||
computed: {
|
||||
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';
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
close () {
|
||||
this.paymentData = {};
|
||||
this.$root.$emit('bv::hide::modal', 'payments-success-modal');
|
||||
},
|
||||
},
|
||||
|
||||
@@ -84,12 +84,16 @@
|
||||
img(src='https://payments.amazon.com/gp/cba/button', :alt="$t('amazonPayments')")
|
||||
.row
|
||||
.col-6
|
||||
h2 {{ $t('giftSubscription') }}
|
||||
h2(v-once) {{ $t('giftSubscription') }}
|
||||
ol
|
||||
li {{ $t('giftSubscriptionText1') }}
|
||||
li {{ $t('giftSubscriptionText2') }}
|
||||
li {{ $t('giftSubscriptionText3') }}
|
||||
h4 {{ $t('giftSubscriptionText4') }}
|
||||
li(v-once) {{ $t('giftSubscriptionText1') }}
|
||||
li(v-once) {{ $t('giftSubscriptionText2') }}
|
||||
li(v-once) {{ $t('giftSubscriptionText3') }}
|
||||
h4(v-once) {{ $t('giftSubscriptionText4') }}
|
||||
.col-6
|
||||
h2 {{ $t('winterPromoGiftHeader') }}
|
||||
p {{ $t('winterPromoGiftDetails1') }}
|
||||
p {{ $t('winterPromoGiftDetails2') }}
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
div(
|
||||
v-for="(groupSets, categoryGroup) in getGroupedCategories(categories)",
|
||||
)
|
||||
h3.classgroup(v-if='categoryGroup !== "spells"')
|
||||
h3.classgroup(v-if='categoryGroup !== "spells" && categoryGroup !== "quests"')
|
||||
span.svg-icon.inline(v-html="icons[categoryGroup]")
|
||||
span.name(:class="categoryGroup") {{ getClassName(categoryGroup) }}
|
||||
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
z-index: 1400; // 1400 is above modal backgrounds
|
||||
|
||||
&-top-pos {
|
||||
&-double {
|
||||
top: 145px;
|
||||
}
|
||||
|
||||
&-normal {
|
||||
top: 65px;
|
||||
}
|
||||
@@ -26,6 +30,7 @@
|
||||
<script>
|
||||
import { mapState } from 'client/libs/store';
|
||||
import notification from './notification';
|
||||
import { CONSTANTS, getLocalSetting } from 'client/libs/userlocalManager';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -39,7 +44,9 @@ export default {
|
||||
notificationsTopPos () {
|
||||
const base = 'notifications-top-pos-';
|
||||
let modifier = '';
|
||||
if (this.userSleeping) {
|
||||
if (this.userSleeping && this.giftingShown) {
|
||||
modifier = 'double';
|
||||
} else if (this.userSleeping || this.giftingShown) {
|
||||
modifier = 'sleeping';
|
||||
} else {
|
||||
modifier = 'normal';
|
||||
@@ -47,5 +54,10 @@ export default {
|
||||
return `${base}${modifier}`;
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
giftingShown: getLocalSetting(CONSTANTS.keyConstants.GIFTING_BANNER_DISPLAY) !== 'dismissed',
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
p {{ $t('needTips') }}
|
||||
div(v-for='step in stepsNum')
|
||||
h3 {{ $t('step'+step) }}
|
||||
p(v-markdown="$t('webStep'+step+'Text')")
|
||||
p(v-markdown="$t('webStep'+step+'Text', stepVars[step])")
|
||||
hr
|
||||
p(v-markdown="$t('overviewQuestions')")
|
||||
p(v-markdown="$t('overviewQuestions', {faqUrl: '/static/faq/', helpGuildUrl: '/groups/guild/5481ccf3-5d2d-48a9-a871-70a7380cee5a'})")
|
||||
</template>
|
||||
|
||||
<style lang='scss'>
|
||||
@@ -31,6 +31,15 @@ export default {
|
||||
data () {
|
||||
return {
|
||||
stepsNum: ['1', '2', '3'],
|
||||
stepVars: {
|
||||
1: {},
|
||||
2: {},
|
||||
3: {
|
||||
partyUrl: '/party',
|
||||
equipUrl: '/inventory/equipment',
|
||||
shopUrl: '/shops/market',
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
@@ -30,15 +30,29 @@
|
||||
a.d-block(v-if="tagsType.key !== 'groups' && !editingTags", @click="editTags(tagsType.key)") {{ $t('editTags2') }}
|
||||
.tags-list.container
|
||||
.row(:class="{'no-gutters': !editingTags}")
|
||||
template(v-if="editingTags && tagsType.key !== 'groups'")
|
||||
.col-6(v-for="(tag, tagIndex) in tagsSnap[tagsType.key]")
|
||||
.inline-edit-input-group.tag-edit-item.input-group
|
||||
input.tag-edit-input.inline-edit-input.form-control(type="text", v-model="tag.name")
|
||||
.input-group-append(@click="removeTag(tagIndex, tagsType.key)")
|
||||
.svg-icon.destroy-icon(v-html="icons.destroy")
|
||||
.col-6(v-if="tagsType.key === 'tags'")
|
||||
input.new-tag-item.edit-tag-item.inline-edit-input.form-control(type="text", :placeholder="$t('newTag')", @keydown.enter="addTag($event, tagsType.key)", v-model="newTag")
|
||||
template(v-else)
|
||||
template(v-if="editingTags && tagsType.key === 'tags'")
|
||||
draggable(
|
||||
v-if="tagsType.key === 'tags'",
|
||||
v-model="tagsSnap[tagsType.key]",
|
||||
class="row"
|
||||
)
|
||||
.col-6(v-for="(tag, tagIndex) in tagsSnap[tagsType.key]")
|
||||
.inline-edit-input-group.tag-edit-item.input-group
|
||||
.svg-icon.inline.drag(v-html="icons.drag")
|
||||
input.tag-edit-input.inline-edit-input.form-control(type="text", v-model="tag.name")
|
||||
.input-group-append(@click="removeTag(tagIndex, tagsType.key)")
|
||||
.svg-icon.destroy-icon(v-html="icons.destroy")
|
||||
|
||||
.col-6.dragSpace
|
||||
input.new-tag-item.edit-tag-item.inline-edit-input.form-control(type="text", :placeholder="$t('newTag')", @keydown.enter="addTag($event, tagsType.key)", v-model="newTag")
|
||||
template(v-if="editingTags && tagsType.key === 'challenges'")
|
||||
.col-6(v-for="(tag, tagIndex) in tagsSnap[tagsType.key]")
|
||||
.inline-edit-input-group.tag-edit-item.input-group
|
||||
input.tag-edit-input.inline-edit-input.form-control(type="text", v-model="tag.name")
|
||||
.input-group-append(@click="removeTag(tagIndex, tagsType.key)")
|
||||
.svg-icon.destroy-icon(v-html="icons.destroy")
|
||||
|
||||
template(v-if="!editingTags || tagsType.key === 'groups'")
|
||||
.col-6(v-for="(tag, tagIndex) in tagsType.tags")
|
||||
.custom-control.custom-checkbox
|
||||
input.custom-control-input(
|
||||
@@ -289,6 +303,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
.drag {
|
||||
cursor: grab;
|
||||
margin: auto 0;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
|
||||
color: #C3C0C7;
|
||||
|
||||
&:hover {
|
||||
color: #878190;
|
||||
}
|
||||
}
|
||||
|
||||
.dragSpace {
|
||||
padding-left: 32px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
.filter-panel {
|
||||
max-width: none;
|
||||
@@ -310,6 +341,7 @@ import habitIcon from 'assets/svg/habit.svg';
|
||||
import dailyIcon from 'assets/svg/daily.svg';
|
||||
import todoIcon from 'assets/svg/todo.svg';
|
||||
import rewardIcon from 'assets/svg/reward.svg';
|
||||
import dragIcon from 'assets/svg/drag_indicator.svg';
|
||||
|
||||
import uuid from 'uuid';
|
||||
import Vue from 'vue';
|
||||
@@ -320,6 +352,7 @@ import taskDefaults from 'common/script/libs/taskDefaults';
|
||||
import brokenTaskModal from './brokenTaskModal';
|
||||
|
||||
import Item from 'client/components/inventory/item.vue';
|
||||
import draggable from 'vuedraggable';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -328,6 +361,7 @@ export default {
|
||||
Item,
|
||||
spells,
|
||||
brokenTaskModal,
|
||||
draggable,
|
||||
},
|
||||
directives: {
|
||||
markdown,
|
||||
@@ -347,6 +381,7 @@ export default {
|
||||
daily: dailyIcon,
|
||||
todo: todoIcon,
|
||||
reward: rewardIcon,
|
||||
drag: dragIcon,
|
||||
}),
|
||||
selectedTags: [],
|
||||
temporarilySelectedTags: [],
|
||||
|
||||
@@ -5,6 +5,7 @@ const CONSTANTS = {
|
||||
EQUIPMENT_DRAWER_STATE: 'equipment-drawer-state',
|
||||
CURRENT_EQUIPMENT_DRAWER_TAB: 'current-equipment-drawer-tab',
|
||||
STABLE_SORT_STATE: 'stable-sort-state',
|
||||
GIFTING_BANNER_DISPLAY: 'gifting-banner-display',
|
||||
},
|
||||
drawerStateValues: {
|
||||
DRAWER_CLOSED: 'drawer-closed',
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import axios from 'axios';
|
||||
|
||||
const STRIPE_PUB_KEY = process.env.STRIPE_PUB_KEY; // eslint-disable-line
|
||||
const STRIPE_PUB_KEY = process.env.STRIPE_PUB_KEY; // eslint-disable-line no-process-env
|
||||
import subscriptionBlocks from '../../common/script/content/subscriptionBlocks';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import encodeParams from 'client/libs/encodeParams';
|
||||
import notificationsMixin from 'client/mixins/notifications';
|
||||
import * as Analytics from 'client/libs/analytics';
|
||||
import { CONSTANTS, setLocalSetting } from 'client/libs/userlocalManager';
|
||||
import pick from 'lodash/pick';
|
||||
|
||||
const habiticaUrl = `${location.protocol}//${location.host}`;
|
||||
|
||||
@@ -43,13 +44,24 @@ export default {
|
||||
let gift = this.encodeGift(data.giftedTo, data.gift);
|
||||
const url = `/paypal/checkout?gift=${gift}`;
|
||||
|
||||
this.openPaypal(url, 'gift');
|
||||
this.openPaypal(url, `gift-${data.gift.type === 'gems' ? 'gems' : 'subscription'}`, data);
|
||||
},
|
||||
openPaypal (url/* , type*/) {
|
||||
openPaypal (url, type, giftData) {
|
||||
const appState = {
|
||||
paymentMethod: 'paypal',
|
||||
paymentCompleted: false,
|
||||
paymentType: type,
|
||||
};
|
||||
|
||||
if (type === 'subscription') {
|
||||
appState.subscriptionKey = this.subscriptionPlan || this.subscription.key;
|
||||
}
|
||||
|
||||
if (type.indexOf('gift-') === 0) {
|
||||
appState.gift = giftData.gift;
|
||||
appState.giftReceiver = giftData.receiverName;
|
||||
}
|
||||
|
||||
setLocalSetting(CONSTANTS.savedAppStateValues.SAVED_APP_STATE, JSON.stringify(appState));
|
||||
window.open(url, '_blank');
|
||||
|
||||
@@ -77,11 +89,18 @@ export default {
|
||||
|
||||
sub = sub && subscriptionBlocks[sub];
|
||||
|
||||
let amount = 500;// 500 = $5
|
||||
let amount = 500; // 500 = $5
|
||||
if (sub) amount = sub.price * 100;
|
||||
if (data.gift && data.gift.type === 'gems') amount = data.gift.gems.amount / 4 * 100;
|
||||
if (data.group) amount = (sub.price + 3 * (data.group.memberCount - 1)) * 100;
|
||||
|
||||
let paymentType;
|
||||
if (sub === false && !data.gift) paymentType = 'gems';
|
||||
if (sub !== false && !data.gift) paymentType = 'subscription';
|
||||
if (data.group || data.groupToCreate) paymentType = 'groupPlan';
|
||||
if (data.gift && data.gift.type === 'gems') paymentType = 'gift-gems';
|
||||
if (data.gift && data.gift.type === 'subscription') paymentType = 'gift-subscription';
|
||||
|
||||
window.StripeCheckout.open({
|
||||
key: STRIPE_PUB_KEY,
|
||||
address: false,
|
||||
@@ -116,7 +135,26 @@ export default {
|
||||
const appState = {
|
||||
paymentMethod: 'stripe',
|
||||
paymentCompleted: true,
|
||||
paymentType,
|
||||
};
|
||||
if (paymentType === 'subscription') {
|
||||
appState.subscriptionKey = sub.key;
|
||||
} else if (paymentType === 'groupPlan') {
|
||||
appState.subscriptionKey = sub.key;
|
||||
|
||||
if (data.groupToCreate) {
|
||||
appState.newGroup = true;
|
||||
appState.group = pick(data.groupToCreate, ['_id', 'memberCount', 'name']);
|
||||
} else {
|
||||
appState.newGroup = false;
|
||||
appState.group = pick(data.group, ['_id', 'memberCount', 'name']);
|
||||
}
|
||||
} else if (paymentType.indexOf('gift-') === 0) {
|
||||
appState.gift = data.gift;
|
||||
appState.giftReceiver = data.receiverName;
|
||||
}
|
||||
|
||||
|
||||
setLocalSetting(CONSTANTS.savedAppStateValues.SAVED_APP_STATE, JSON.stringify(appState));
|
||||
|
||||
let newGroup = response.data.data;
|
||||
@@ -191,6 +229,7 @@ export default {
|
||||
if (data.gift) {
|
||||
if (data.gift.gems && data.gift.gems.amount && data.gift.gems.amount <= 0) return;
|
||||
data.gift.uuid = data.giftedTo;
|
||||
this.amazonPayments.giftReceiver = data.receiverName;
|
||||
}
|
||||
|
||||
if (data.subscription) {
|
||||
@@ -202,7 +241,11 @@ export default {
|
||||
this.amazonPayments.groupId = data.groupId;
|
||||
}
|
||||
|
||||
if (data.groupToCreate) {
|
||||
if (data.group) { // upgrading a group
|
||||
this.amazonPayments.group = data.group;
|
||||
}
|
||||
|
||||
if (data.groupToCreate) { // creating a group
|
||||
this.amazonPayments.groupToCreate = data.groupToCreate;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import axios from 'axios';
|
||||
|
||||
const LOCALSTORAGE_AUTH_KEY = 'habit-mobile-settings';
|
||||
const LOCALSTORAGE_SOCIAL_AUTH_KEY = 'hello'; // Used by hello.js for social auth
|
||||
|
||||
export async function register (store, params) {
|
||||
let url = '/api/v4/user/auth/local/register';
|
||||
@@ -84,7 +83,6 @@ export async function socialAuth (store, params) {
|
||||
}
|
||||
|
||||
export function logout () {
|
||||
localStorage.removeItem(LOCALSTORAGE_AUTH_KEY);
|
||||
localStorage.removeItem(LOCALSTORAGE_SOCIAL_AUTH_KEY);
|
||||
localStorage.clear();
|
||||
window.location.href = '/logout-server';
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ export async function updateTag (store, payload) {
|
||||
export async function sortTag (store, payload) {
|
||||
let url = 'api/v4/reorder-tags';
|
||||
let response = await axios.post(url, {
|
||||
tagDetails: payload.tagDetails,
|
||||
tagId: payload.tagId,
|
||||
to: payload.to,
|
||||
});
|
||||
return response.data.data;
|
||||
|
||||
@@ -401,5 +401,12 @@
|
||||
"backgroundFrostyForestText": "Ледена гора",
|
||||
"backgroundFrostyForestNotes": "Пригответе се за поход през ледена гора.",
|
||||
"backgroundSnowyDayFireplaceText": "Огнище в снежен ден",
|
||||
"backgroundSnowyDayFireplaceNotes": "Сгушете се пред огнището в снежен ден."
|
||||
"backgroundSnowyDayFireplaceNotes": "Сгушете се пред огнището в снежен ден.",
|
||||
"backgrounds012019": "КОМПЛЕКТ 56: януари 2019 г.",
|
||||
"backgroundAvalancheText": "Лавина",
|
||||
"backgroundAvalancheNotes": "Избягайте от страховитата мощ на лавина.",
|
||||
"backgroundArchaeologicalDigText": "Археологически разкопки",
|
||||
"backgroundArchaeologicalDigNotes": "Разкрийте тайните на древността в археологически разкопки.",
|
||||
"backgroundScribesWorkshopText": "Работилница на книжник",
|
||||
"backgroundScribesWorkshopNotes": "Напишете следващия си списък в работилница на книжник."
|
||||
}
|
||||
@@ -179,6 +179,9 @@
|
||||
"questEggAlligatorText": "Алигатор",
|
||||
"questEggAlligatorMountText": "Алигатор",
|
||||
"questEggAlligatorAdjective": "хитър",
|
||||
"questEggVelociraptorText": "Велоцираптор",
|
||||
"questEggVelociraptorMountText": "Велоцираптор",
|
||||
"questEggVelociraptorAdjective": "умен",
|
||||
"eggNotes": "Намерете излюпваща отвара, която да излеете върху това яйце и от него ще се излюпи <%= eggAdjective(locale) %> <%= eggText(locale) %>.",
|
||||
"hatchingPotionBase": "Нормален цвят",
|
||||
"hatchingPotionWhite": "Бял цвят",
|
||||
@@ -207,6 +210,7 @@
|
||||
"hatchingPotionGlass": "Стъкло",
|
||||
"hatchingPotionGlow": "Светещо в тъмното",
|
||||
"hatchingPotionFrost": "Скреж",
|
||||
"hatchingPotionIcySnow": "Леден сняг",
|
||||
"hatchingPotionNotes": "Излейте това върху яйце и от него ще се излюпи любимец с(ъс) <%= potText(locale) %>.",
|
||||
"premiumPotionAddlNotes": "Не може да се използва върху яйца за любимци от мисии.",
|
||||
"foodMeat": "Месо",
|
||||
|
||||