Compare commits
94 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a5fc909f0d | |||
| 30a5192e19 | |||
| 79c0499672 | |||
| 490531cc76 | |||
| 8cd4c502bc | |||
| d8cacb653e | |||
| 59436a8bf7 | |||
| 6fade19f27 | |||
| 15d028a281 | |||
| e028232527 | |||
| e3b270a62e | |||
| fceeacec3b | |||
| f93c67e57c | |||
| 192dc26fbe | |||
| 1c1f270f64 | |||
| 483768f4a7 | |||
| 65031cef3a | |||
| 2fc1f46359 | |||
| 30fd530576 | |||
| f79999fde7 | |||
| 90d6e443ba | |||
| 4ed1082558 | |||
| 00717eda76 | |||
| d1b86e6c14 | |||
| c813afba44 | |||
| d49db6d367 | |||
| d6835aec56 | |||
| 960f7b5886 | |||
| ff57e31f4f | |||
| 6e21d154ae | |||
| fe5beac91b | |||
| 52fd6a1451 | |||
| ae445555e9 | |||
| c4fc6671b4 | |||
| e7a096158e | |||
| 98473fcfaa | |||
| e4300fc714 | |||
| ffba435923 | |||
| 1f44444a50 | |||
| 061d990e39 | |||
| 71f4e6bc08 | |||
| 659f160e22 | |||
| 5f27bc5f90 | |||
| 074837b274 | |||
| aa517e0ad6 | |||
| 5ca489dee7 | |||
| fe39ef72ff | |||
| eee5f2f1df | |||
| fd8572c28a | |||
| f161987e1e | |||
| 2304d970a5 | |||
| 25ed05ab0a | |||
| 6f5b9ef119 | |||
| c64ea0a9a9 | |||
| 2e36b896d4 | |||
| 6fe73d431e | |||
| 998621cefe | |||
| 67bb179c25 | |||
| c875861dab | |||
| 418c18ddb2 | |||
| 0caab5c8d0 | |||
| 218e65b04b | |||
| fcd7ba77a7 | |||
| b0d177643c | |||
| c0e0b10a95 | |||
| 0bee2caf2e | |||
| e56d097b3a | |||
| 8c63a9e31f | |||
| 28ed9d8bcc | |||
| 36ead77e0c | |||
| e7969987ec | |||
| 97021e3422 | |||
| 218d47d64a | |||
| bdfc23717e | |||
| 464cd87736 | |||
| 67a8eebb96 | |||
| cfc0f6a3ac | |||
| 9f76db12bd | |||
| 70192e4935 | |||
| 5cd4ead9d1 | |||
| 87cd000bb8 | |||
| 0de5d8273b | |||
| 379898cc4d | |||
| adeaa6c754 | |||
| c880596a77 | |||
| a35f04be46 | |||
| 5632031f16 | |||
| 07bc374078 | |||
| c862bdb76a | |||
| b596576c53 | |||
| 9fd26a88ea | |||
| 76860fe3f8 | |||
| b16e700de5 | |||
| b75e65f42d |
@@ -39,6 +39,7 @@
|
||||
"NEW_RELIC_API_KEY":"NEW_RELIC_API_KEY",
|
||||
"GA_ID": "GA_ID",
|
||||
"AMPLITUDE_KEY": "AMPLITUDE_KEY",
|
||||
"AMPLITUDE_SECRET": "AMPLITUDE_SECRET",
|
||||
"AMAZON_PAYMENTS": {
|
||||
"SELLER_ID": "SELLER_ID",
|
||||
"CLIENT_ID": "CLIENT_ID",
|
||||
@@ -88,12 +89,6 @@
|
||||
"USERNAME": "admin",
|
||||
"PASSWORD": "password"
|
||||
},
|
||||
"PUSHER": {
|
||||
"ENABLED": "false",
|
||||
"APP_ID": "appId",
|
||||
"KEY": "key",
|
||||
"SECRET": "secret"
|
||||
},
|
||||
"SLACK": {
|
||||
"FLAGGING_URL": "https://hooks.slack.com/services/id/id/id",
|
||||
"FLAGGING_FOOTER_LINK": "https://habitrpg.github.io/flag-o-rama/",
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import monk from 'monk';
|
||||
import nconf from 'nconf';
|
||||
|
||||
/*
|
||||
* Output data on users who completed all the To-Do tasks in the 2018 Back-to-School Challenge.
|
||||
* User ID,Profile Name
|
||||
*/
|
||||
const CONNECTION_STRING = nconf.get('MIGRATION_CONNECT_STRING');
|
||||
const CHALLENGE_ID = '0acb1d56-1660-41a4-af80-9259f080b62b';
|
||||
|
||||
let dbUsers = monk(CONNECTION_STRING).get('users', { castIds: false });
|
||||
let dbTasks = monk(CONNECTION_STRING).get('tasks', { castIds: false });
|
||||
|
||||
function usersReport() {
|
||||
console.info('User ID,Profile Name');
|
||||
let userCount = 0;
|
||||
|
||||
dbUsers.find(
|
||||
{challenges: CHALLENGE_ID},
|
||||
{fields:
|
||||
{_id: 1, 'profile.name': 1}
|
||||
},
|
||||
).each((user, {close, pause, resume}) => {
|
||||
pause();
|
||||
userCount++;
|
||||
let completedTodos = 0;
|
||||
return dbTasks.find(
|
||||
{
|
||||
userId: user._id,
|
||||
'challenge.id': CHALLENGE_ID,
|
||||
type: 'todo',
|
||||
},
|
||||
{fields: {completed: 1}}
|
||||
).each((task) => {
|
||||
if (task.completed) completedTodos++;
|
||||
}).then(() => {
|
||||
if (completedTodos >= 7) {
|
||||
console.info(`${user._id},${user.profile.name}`);
|
||||
}
|
||||
resume();
|
||||
});
|
||||
}).then(() => {
|
||||
console.info(`${userCount} users reviewed`);
|
||||
return process.exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = usersReport;
|
||||
@@ -8,6 +8,7 @@ const authorUuid = 'ed4c688c-6652-4a92-9d03-a5a79844174a'; // ... own data is do
|
||||
|
||||
const monk = require('monk');
|
||||
const nconf = require('nconf');
|
||||
const uuid = require('uuid').v4;
|
||||
|
||||
const Inbox = require('../website/server/models/message').inboxModel;
|
||||
const connectionString = nconf.get('MIGRATION_CONNECT_STRING'); // FOR TEST DATABASE
|
||||
@@ -84,16 +85,39 @@ function updateUser (user) {
|
||||
return newMsg.toJSON();
|
||||
});
|
||||
|
||||
return dbInboxes.insert(newInboxMessages)
|
||||
.then(() => {
|
||||
const promises = newInboxMessages.map(newMsg => {
|
||||
return (async function fn () {
|
||||
const existing = await dbInboxes.find({_id: newMsg._id});
|
||||
|
||||
if (existing.length > 0) {
|
||||
if (
|
||||
existing[0].ownerId === newMsg.ownerId &&
|
||||
existing[0].text === newMsg.text &&
|
||||
existing[0].uuid === newMsg.uuid &&
|
||||
existing[0].sent === newMsg.sent
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
newMsg.id = newMsg._id = uuid();
|
||||
}
|
||||
|
||||
return newMsg;
|
||||
})();
|
||||
});
|
||||
|
||||
return Promise.all(promises)
|
||||
.then((filteredNewMsg) => {
|
||||
filteredNewMsg = filteredNewMsg.filter(m => Boolean(m && m.id && m._id && m.id == m._id));
|
||||
return dbInboxes.insert(filteredNewMsg);
|
||||
}).then(() => {
|
||||
return dbUsers.update({_id: user._id}, {
|
||||
$set: {
|
||||
migration: migrationName,
|
||||
'inbox.messages': {},
|
||||
},
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
}).catch((err) => {
|
||||
console.log(err);
|
||||
return exiting(1, `ERROR! ${ err}`);
|
||||
});
|
||||
@@ -0,0 +1,107 @@
|
||||
const MIGRATION_NAME = '20181003_username_email.js';
|
||||
let authorName = 'Sabe'; // in case script author needs to know when their ...
|
||||
let authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is done
|
||||
|
||||
/*
|
||||
* Send emails to eligible users announcing upcoming username changes
|
||||
*/
|
||||
|
||||
import monk from 'monk';
|
||||
import nconf from 'nconf';
|
||||
import { sendTxn } from '../../website/server/libs/email';
|
||||
const CONNECTION_STRING = nconf.get('MIGRATION_CONNECT_STRING');
|
||||
let dbUsers = monk(CONNECTION_STRING).get('users', { castIds: false });
|
||||
|
||||
function processUsers (lastId) {
|
||||
// specify a query to limit the affected users (empty for all users):
|
||||
let query = {
|
||||
migration: {$ne: MIGRATION_NAME},
|
||||
'auth.timestamps.loggedin': {$gt: new Date('2018-04-01')},
|
||||
};
|
||||
|
||||
if (lastId) {
|
||||
query._id = {
|
||||
$gt: lastId,
|
||||
};
|
||||
}
|
||||
|
||||
dbUsers.find(query, {
|
||||
sort: {_id: 1},
|
||||
limit: 100,
|
||||
fields: [
|
||||
'_id',
|
||||
'auth',
|
||||
'preferences',
|
||||
'profile',
|
||||
], // specify fields we are interested in to limit retrieved data (empty if we're not reading data):
|
||||
})
|
||||
.then(updateUsers)
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
return exiting(1, `ERROR! ${ err}`);
|
||||
});
|
||||
}
|
||||
|
||||
let progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
function updateUsers (users) {
|
||||
if (!users || users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
displayData();
|
||||
return;
|
||||
}
|
||||
|
||||
let userPromises = users.map(updateUser);
|
||||
let lastUser = users[users.length - 1];
|
||||
|
||||
return Promise.all(userPromises)
|
||||
.then(() => delay(7000))
|
||||
.then(() => {
|
||||
processUsers(lastUser._id);
|
||||
});
|
||||
}
|
||||
|
||||
function updateUser (user) {
|
||||
count++;
|
||||
|
||||
dbUsers.update({_id: user._id}, {$set: {migration: MIGRATION_NAME}});
|
||||
|
||||
sendTxn(
|
||||
user,
|
||||
'username-change',
|
||||
[{name: 'UNSUB_EMAIL_TYPE_URL', content: '/user/settings/notifications?unsubFrom=importantAnnouncements'},
|
||||
{name: 'LOGIN_NAME', content: user.auth.local.username}]
|
||||
);
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
if (user._id === authorUuid) console.warn(`${authorName} processed`);
|
||||
}
|
||||
|
||||
function displayData () {
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
return exiting(0);
|
||||
}
|
||||
|
||||
function delay (t, v) {
|
||||
return new Promise(function batchPause (resolve) {
|
||||
setTimeout(resolve.bind(null, v), t);
|
||||
});
|
||||
}
|
||||
|
||||
function exiting (code, msg) {
|
||||
code = code || 0; // 0 = success
|
||||
if (code && !msg) {
|
||||
msg = 'ERROR!';
|
||||
}
|
||||
if (msg) {
|
||||
if (code) {
|
||||
console.error(msg);
|
||||
} else {
|
||||
console.log(msg);
|
||||
}
|
||||
}
|
||||
process.exit(code);
|
||||
}
|
||||
|
||||
module.exports = processUsers;
|
||||
@@ -17,5 +17,12 @@ function setUpServer () {
|
||||
setUpServer();
|
||||
|
||||
// Replace this with your migration
|
||||
const processUsers = require('./users/takeThis.js');
|
||||
processUsers();
|
||||
const processUsers = require('../scripts/gdpr-delete-users.js');
|
||||
processUsers()
|
||||
.then(function success () {
|
||||
process.exit(0);
|
||||
})
|
||||
.catch(function failure (err) {
|
||||
console.log(err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/* eslint-disable no-console */
|
||||
const MIGRATION_NAME = '20181023_veteran_pet_ladder';
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
|
||||
function processUsers (lastId) {
|
||||
let query = {
|
||||
migration: {$ne: MIGRATION_NAME},
|
||||
'flags.verifiedUsername': true,
|
||||
};
|
||||
|
||||
let fields = {
|
||||
'items.pets': 1,
|
||||
};
|
||||
|
||||
if (lastId) {
|
||||
query._id = {
|
||||
$gt: lastId,
|
||||
};
|
||||
}
|
||||
|
||||
return User.find(query)
|
||||
.limit(250)
|
||||
.sort({_id: 1})
|
||||
.select(fields)
|
||||
.then(updateUsers)
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
return exiting(1, `ERROR! ${err}`);
|
||||
});
|
||||
}
|
||||
|
||||
let progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
function updateUsers (users) {
|
||||
if (!users || users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
displayData();
|
||||
return;
|
||||
}
|
||||
|
||||
let userPromises = users.map(updateUser);
|
||||
let lastUser = users[users.length - 1];
|
||||
|
||||
return Promise.all(userPromises)
|
||||
.then(() => {
|
||||
processUsers(lastUser._id);
|
||||
});
|
||||
}
|
||||
|
||||
function updateUser (user) {
|
||||
count++;
|
||||
|
||||
let set = {migration: MIGRATION_NAME};
|
||||
|
||||
if (user.items.pets['Bear-Veteran']) {
|
||||
set['items.pets.Fox-Veteran'] = 5;
|
||||
} else if (user.items.pets['Lion-Veteran']) {
|
||||
set['items.pets.Bear-Veteran'] = 5;
|
||||
} else if (user.items.pets['Tiger-Veteran']) {
|
||||
set['items.pets.Lion-Veteran'] = 5;
|
||||
} else if (user.items.pets['Wolf-Veteran']) {
|
||||
set['items.pets.Tiger-Veteran'] = 5;
|
||||
} else {
|
||||
set['items.pets.Wolf-Veteran'] = 5;
|
||||
}
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
|
||||
return user.update({_id: user._id}, {$set: set}).exec();
|
||||
}
|
||||
|
||||
function displayData () {
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
return exiting(0);
|
||||
}
|
||||
|
||||
function exiting (code, msg) {
|
||||
code = code || 0; // 0 = success
|
||||
if (code && !msg) {
|
||||
msg = 'ERROR!';
|
||||
}
|
||||
if (msg) {
|
||||
if (code) {
|
||||
console.error(msg);
|
||||
} else {
|
||||
console.log(msg);
|
||||
}
|
||||
}
|
||||
process.exit(code);
|
||||
}
|
||||
|
||||
module.exports = processUsers;
|
||||
@@ -8,7 +8,7 @@ const authorUuid = '7f14ed62-5408-4e1b-be83-ada62d504931'; // ... own data is do
|
||||
/*
|
||||
* Award this month's mystery items to subscribers
|
||||
*/
|
||||
const MYSTERY_ITEMS = ['armor_mystery_201809', 'head_mystery_201809'];
|
||||
const MYSTERY_ITEMS = ['armor_mystery_201810', 'head_mystery_201810'];
|
||||
const CONNECTION_STRING = nconf.get('MIGRATION_CONNECT_STRING');
|
||||
|
||||
let dbUsers = monk(CONNECTION_STRING).get('users', { castIds: false });
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
|
||||
"version": "4.64.1",
|
||||
"version": "4.67.1",
|
||||
"main": "./website/server/index.js",
|
||||
"dependencies": {
|
||||
"@slack/client": "^3.8.1",
|
||||
@@ -11,7 +11,7 @@
|
||||
"apidoc": "^0.17.5",
|
||||
"apn": "^2.2.0",
|
||||
"autoprefixer": "^8.5.0",
|
||||
"aws-sdk": "^2.239.1",
|
||||
"aws-sdk": "^2.329.0",
|
||||
"axios": "^0.18.0",
|
||||
"axios-progress-bar": "^1.2.0",
|
||||
"babel-core": "^6.26.3",
|
||||
@@ -35,7 +35,7 @@
|
||||
"coupon-code": "^0.4.5",
|
||||
"cross-env": "^5.1.5",
|
||||
"css-loader": "^0.28.11",
|
||||
"csv-stringify": "^3.0.0",
|
||||
"csv-stringify": "^4.3.1",
|
||||
"cwait": "^1.1.1",
|
||||
"domain-middleware": "~0.1.0",
|
||||
"express": "^4.16.3",
|
||||
@@ -53,19 +53,19 @@
|
||||
"hellojs": "^1.15.1",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"image-size": "^0.6.2",
|
||||
"in-app-purchase": "^1.9.4",
|
||||
"in-app-purchase": "^1.10.2",
|
||||
"intro.js": "^2.9.3",
|
||||
"jquery": ">=3.0.0",
|
||||
"js2xmlparser": "^3.0.0",
|
||||
"lodash": "^4.17.10",
|
||||
"merge-stream": "^1.0.0",
|
||||
"method-override": "^2.3.5",
|
||||
"method-override": "^3.0.0",
|
||||
"moment": "^2.22.1",
|
||||
"moment-recur": "^1.0.7",
|
||||
"mongoose": "^5.1.3",
|
||||
"mongoose": "^5.3.4",
|
||||
"morgan": "^1.7.0",
|
||||
"nconf": "^0.10.0",
|
||||
"node-gcm": "^0.14.4",
|
||||
"node-gcm": "^1.0.2",
|
||||
"node-sass": "^4.9.0",
|
||||
"nodemailer": "^4.6.4",
|
||||
"ora": "^2.1.0",
|
||||
@@ -79,7 +79,6 @@
|
||||
"postcss-easy-import": "^3.0.0",
|
||||
"ps-tree": "^1.0.0",
|
||||
"pug": "^2.0.3",
|
||||
"pusher": "^1.3.0",
|
||||
"rimraf": "^2.4.3",
|
||||
"sass-loader": "^7.0.0",
|
||||
"shelljs": "^0.8.2",
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/* eslint-disable no-console */
|
||||
import axios from 'axios';
|
||||
import { model as User } from '../website/server/models/user';
|
||||
import nconf from 'nconf';
|
||||
|
||||
const AMPLITUDE_KEY = nconf.get('AMPLITUDE_KEY');
|
||||
const AMPLITUDE_SECRET = nconf.get('AMPLITUDE_SECRET');
|
||||
const BASE_URL = nconf.get('BASE_URL');
|
||||
|
||||
async function _deleteAmplitudeData (userId, email) {
|
||||
const response = await axios.post(
|
||||
'https://amplitude.com/api/2/deletions/users',
|
||||
{
|
||||
user_ids: userId, // eslint-disable-line camelcase
|
||||
requester: email,
|
||||
},
|
||||
{
|
||||
auth: {
|
||||
username: AMPLITUDE_KEY,
|
||||
password: AMPLITUDE_SECRET,
|
||||
},
|
||||
}
|
||||
).catch((err) => {
|
||||
console.log(err.response.data);
|
||||
});
|
||||
|
||||
if (response) console.log(`${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
async function _deleteHabiticaData (user) {
|
||||
await User.update(
|
||||
{_id: user._id},
|
||||
{$set: {
|
||||
'auth.local.passwordHashMethod': 'bcrypt',
|
||||
'auth.local.hashed_password': '$2a$10$QDnNh1j1yMPnTXDEOV38xOePEWFd4X8DSYwAM8XTmqmacG5X0DKjW',
|
||||
}}
|
||||
);
|
||||
const response = await axios.delete(
|
||||
`${BASE_URL}/api/v3/user`,
|
||||
{
|
||||
data: {
|
||||
password: 'test',
|
||||
},
|
||||
headers: {
|
||||
'x-api-user': user._id,
|
||||
'x-api-key': user.apiToken,
|
||||
},
|
||||
}
|
||||
).catch((err) => {
|
||||
console.log(err.response.data);
|
||||
});
|
||||
|
||||
if (response) {
|
||||
console.log(`${response.status} ${response.statusText}`);
|
||||
if (response.status === 200) console.log(`${user._id} removed. Last login: ${user.auth.timestamps.loggedin}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function _processEmailAddress (email) {
|
||||
const emailRegex = new RegExp(`^${email}`, 'i');
|
||||
const users = await User.find({
|
||||
$or: [
|
||||
{'auth.local.email': emailRegex},
|
||||
{'auth.facebook.emails.value': emailRegex},
|
||||
{'auth.google.emails.value': emailRegex},
|
||||
]},
|
||||
{
|
||||
_id: 1,
|
||||
apiToken: 1,
|
||||
auth: 1,
|
||||
}).exec();
|
||||
|
||||
if (users.length < 1) {
|
||||
console.log(`No users found with email address ${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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function deleteUserData (emails) {
|
||||
const emailPromises = emails.map(_processEmailAddress);
|
||||
return Promise.all(emailPromises);
|
||||
}
|
||||
|
||||
module.exports = deleteUserData;
|
||||
@@ -5,10 +5,17 @@ describe('Base model plugin', () => {
|
||||
let schema;
|
||||
|
||||
beforeEach(() => {
|
||||
schema = new mongoose.Schema();
|
||||
schema = new mongoose.Schema({}, {
|
||||
typeKey: '$type',
|
||||
});
|
||||
sandbox.stub(schema, 'add');
|
||||
});
|
||||
|
||||
it('throws if "typeKey" is not set to $type', () => {
|
||||
const schemaWithoutTypeKey = new mongoose.Schema();
|
||||
expect(() => schemaWithoutTypeKey.plugin(baseModel)).to.throw;
|
||||
});
|
||||
|
||||
it('adds a _id field to the schema', () => {
|
||||
schema.plugin(baseModel);
|
||||
|
||||
|
||||
@@ -446,6 +446,19 @@ describe('payments/index', () => {
|
||||
fakeClock.restore();
|
||||
});
|
||||
|
||||
it('does not add a notification for mystery items if none was awarded', async () => {
|
||||
const noMysteryItemTimeframe = 1462183920000; // May 2nd 2016
|
||||
let fakeClock = sinon.useFakeTimers(noMysteryItemTimeframe);
|
||||
data = { paymentMethod: 'PaymentMethod', user, sub: { key: 'basic_3mo' } };
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.mysteryItems).to.have.a.lengthOf(0);
|
||||
expect(user.notifications.find(n => n.type === 'NEW_MYSTERY_ITEMS')).to.be.undefined;
|
||||
|
||||
fakeClock.restore();
|
||||
});
|
||||
|
||||
it('does not award mystery item when user already owns the item', async () => {
|
||||
let mayMysteryItemTimeframe = 1464725113000; // May 31st 2016
|
||||
let fakeClock = sinon.useFakeTimers(mayMysteryItemTimeframe);
|
||||
|
||||
@@ -1932,28 +1932,54 @@ describe('Group Model', () => {
|
||||
|
||||
context('hasNotCancelled', () => {
|
||||
it('returns false if group does not have customer id', () => {
|
||||
expect(party.hasNotCancelled()).to.be.undefined;
|
||||
expect(party.hasNotCancelled()).to.be.false;
|
||||
});
|
||||
|
||||
it('returns true if party does not have plan.dateTerminated', () => {
|
||||
it('returns true if group does not have plan.dateTerminated', () => {
|
||||
party.purchased.plan.customerId = 'test-id';
|
||||
|
||||
expect(party.hasNotCancelled()).to.be.true;
|
||||
});
|
||||
|
||||
it('returns false if party if plan.dateTerminated is after today', () => {
|
||||
it('returns false if group if plan.dateTerminated is after today', () => {
|
||||
party.purchased.plan.customerId = 'test-id';
|
||||
party.purchased.plan.dateTerminated = moment().add(1, 'days').toDate();
|
||||
|
||||
expect(party.hasNotCancelled()).to.be.false;
|
||||
});
|
||||
|
||||
it('returns false if party if plan.dateTerminated is before today', () => {
|
||||
it('returns false if group if plan.dateTerminated is before today', () => {
|
||||
party.purchased.plan.customerId = 'test-id';
|
||||
party.purchased.plan.dateTerminated = moment().subtract(1, 'days').toDate();
|
||||
|
||||
expect(party.hasNotCancelled()).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
context('hasCancelled', () => {
|
||||
it('returns false if group does not have customer id', () => {
|
||||
expect(party.hasCancelled()).to.be.false;
|
||||
});
|
||||
|
||||
it('returns false if group does not have plan.dateTerminated', () => {
|
||||
party.purchased.plan.customerId = 'test-id';
|
||||
|
||||
expect(party.hasCancelled()).to.be.false;
|
||||
});
|
||||
|
||||
it('returns true if group if plan.dateTerminated is after today', () => {
|
||||
party.purchased.plan.customerId = 'test-id';
|
||||
party.purchased.plan.dateTerminated = moment().add(1, 'days').toDate();
|
||||
|
||||
expect(party.hasCancelled()).to.be.true;
|
||||
});
|
||||
|
||||
it('returns false if group if plan.dateTerminated is before today', () => {
|
||||
party.purchased.plan.customerId = 'test-id';
|
||||
party.purchased.plan.dateTerminated = moment().subtract(1, 'days').toDate();
|
||||
|
||||
expect(party.hasCancelled()).to.be.false;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -315,9 +315,8 @@ describe('User Model', () => {
|
||||
user = new User();
|
||||
});
|
||||
|
||||
|
||||
it('returns false if user does not have customer id', () => {
|
||||
expect(user.hasNotCancelled()).to.be.undefined;
|
||||
expect(user.hasNotCancelled()).to.be.false;
|
||||
});
|
||||
|
||||
it('returns true if user does not have plan.dateTerminated', () => {
|
||||
@@ -341,6 +340,38 @@ describe('User Model', () => {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
context('hasCancelled', () => {
|
||||
let user;
|
||||
beforeEach(() => {
|
||||
user = new User();
|
||||
});
|
||||
|
||||
it('returns false if user does not have customer id', () => {
|
||||
expect(user.hasCancelled()).to.be.false;
|
||||
});
|
||||
|
||||
it('returns false if user does not have plan.dateTerminated', () => {
|
||||
user.purchased.plan.customerId = 'test-id';
|
||||
|
||||
expect(user.hasCancelled()).to.be.false;
|
||||
});
|
||||
|
||||
it('returns true if user if plan.dateTerminated is after today', () => {
|
||||
user.purchased.plan.customerId = 'test-id';
|
||||
user.purchased.plan.dateTerminated = moment().add(1, 'days').toDate();
|
||||
|
||||
expect(user.hasCancelled()).to.be.true;
|
||||
});
|
||||
|
||||
it('returns false if user if plan.dateTerminated is before today', () => {
|
||||
user.purchased.plan.customerId = 'test-id';
|
||||
user.purchased.plan.dateTerminated = moment().subtract(1, 'days').toDate();
|
||||
|
||||
expect(user.hasCancelled()).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
context('pre-save hook', () => {
|
||||
it('does not try to award achievements when achievements or items not selected in query', async () => {
|
||||
let user = new User();
|
||||
|
||||
@@ -79,7 +79,7 @@ describe('GET /groups/:groupId/invites', () => {
|
||||
expect(member).to.have.all.keys(['_id', 'id', 'profile']);
|
||||
expect(member.profile).to.have.all.keys(['name']);
|
||||
});
|
||||
});
|
||||
}).timeout(10000);
|
||||
|
||||
it('supports using req.query.lastId to get more invites', async function () {
|
||||
this.timeout(30000); // @TODO: times out after 8 seconds
|
||||
|
||||
@@ -417,7 +417,7 @@ describe('Post /groups/:groupId/invite', () => {
|
||||
expect(await inviter.post(`/groups/${group._id}/invite`, {
|
||||
uuids: generatedInvites.map(invite => invite._id),
|
||||
})).to.be.an('array');
|
||||
});
|
||||
}).timeout(10000);
|
||||
|
||||
// @TODO: Add this after we are able to mock the group plan route
|
||||
xit('returns an error when a non-leader invites to a group plan', async () => {
|
||||
@@ -564,7 +564,7 @@ describe('Post /groups/:groupId/invite', () => {
|
||||
expect(await inviter.post(`/groups/${party._id}/invite`, {
|
||||
uuids: generatedInvites.map(invite => invite._id),
|
||||
})).to.be.an('array');
|
||||
});
|
||||
}).timeout(10000);
|
||||
|
||||
it('does not allow 30+ members in a party', async () => {
|
||||
let invitesToGenerate = [];
|
||||
@@ -582,6 +582,6 @@ describe('Post /groups/:groupId/invite', () => {
|
||||
error: 'BadRequest',
|
||||
message: t('partyExceedsMembersLimit', {maxMembersParty: PARTY_LIMIT_MEMBERS}),
|
||||
});
|
||||
});
|
||||
}).timeout(10000);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -56,5 +56,5 @@ describe('GET /hall/patrons', () => {
|
||||
expect(morePatrons.length).to.equal(2);
|
||||
expect(morePatrons[0].backer.tier).to.equal(2);
|
||||
expect(morePatrons[1].backer.tier).to.equal(1);
|
||||
});
|
||||
}).timeout(10000);
|
||||
});
|
||||
|
||||
@@ -20,8 +20,8 @@ describe('DELETE user message', () => {
|
||||
|
||||
messagesId = Object.keys(userRes.inbox.messages);
|
||||
expect(messagesId.length).to.eql(2);
|
||||
expect(userRes.inbox.messages[messagesId[0]].text).to.eql('first');
|
||||
expect(userRes.inbox.messages[messagesId[1]].text).to.eql('second');
|
||||
expect(userRes.inbox.messages[messagesId[0]].text).to.eql('second');
|
||||
expect(userRes.inbox.messages[messagesId[1]].text).to.eql('first');
|
||||
});
|
||||
|
||||
it('one message', async () => {
|
||||
@@ -31,7 +31,7 @@ describe('DELETE user message', () => {
|
||||
|
||||
let userRes = await user.get('/user');
|
||||
expect(Object.keys(userRes.inbox.messages).length).to.eql(1);
|
||||
expect(userRes.inbox.messages[messagesId[0]].text).to.eql('second');
|
||||
expect(userRes.inbox.messages[messagesId[0]].text).to.eql('first');
|
||||
});
|
||||
|
||||
it('clear all', async () => {
|
||||
|
||||
@@ -39,14 +39,16 @@ describe('POST /user/push-devices', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if user already has the push device', async () => {
|
||||
it('fails silently if user already has the push device', async () => {
|
||||
await user.post('/user/push-devices', {type, regId});
|
||||
await expect(user.post('/user/push-devices', {type, regId}))
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: t('pushDeviceAlreadyAdded'),
|
||||
});
|
||||
const response = await user.post('/user/push-devices', {type, regId});
|
||||
await user.sync();
|
||||
|
||||
expect(response.message).to.equal(t('pushDeviceAdded'));
|
||||
expect(response.data[0].type).to.equal(type);
|
||||
expect(response.data[0].regId).to.equal(regId);
|
||||
expect(user.pushDevices[0].type).to.equal(type);
|
||||
expect(user.pushDevices[0].regId).to.equal(regId);
|
||||
});
|
||||
|
||||
it('adds a push device to the user', async () => {
|
||||
|
||||
@@ -276,7 +276,7 @@ describe('POST /user/auth/local/register', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('enrolls new users in an A/B test', async () => {
|
||||
xit('enrolls new users in an A/B test', async () => {
|
||||
let username = generateRandomUserName();
|
||||
let email = `${username}@example.com`;
|
||||
let password = 'password';
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
/* eslint-disable camelcase */
|
||||
|
||||
import {
|
||||
generateUser,
|
||||
requester,
|
||||
translate as t,
|
||||
} from '../../../../../helpers/api-integration/v3';
|
||||
import { v4 as generateUUID } from 'uuid';
|
||||
|
||||
describe('POST /user/auth/pusher', () => {
|
||||
let user;
|
||||
let endpoint = '/user/auth/pusher';
|
||||
|
||||
beforeEach(async () => {
|
||||
user = await generateUser();
|
||||
});
|
||||
|
||||
it('requires authentication', async () => {
|
||||
let api = requester();
|
||||
|
||||
await expect(api.post(endpoint)).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: t('missingAuthHeaders'),
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if req.body.socket_id is missing', async () => {
|
||||
await expect(user.post(endpoint, {
|
||||
channel_name: '123',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('invalidReqParams'),
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if req.body.channel_name is missing', async () => {
|
||||
await expect(user.post(endpoint, {
|
||||
socket_id: '123',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('invalidReqParams'),
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if req.body.channel_name is badly formatted', async () => {
|
||||
await expect(user.post(endpoint, {
|
||||
channel_name: '123',
|
||||
socket_id: '123',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: 'Invalid Pusher channel type.',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if an invalid channel type is passed', async () => {
|
||||
await expect(user.post(endpoint, {
|
||||
channel_name: 'invalid-group-123',
|
||||
socket_id: '123',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: 'Invalid Pusher channel type.',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if an invalid resource type is passed', async () => {
|
||||
await expect(user.post(endpoint, {
|
||||
channel_name: 'presence-user-123',
|
||||
socket_id: '123',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: 'Invalid Pusher resource type.',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if an invalid resource id is passed', async () => {
|
||||
await expect(user.post(endpoint, {
|
||||
channel_name: 'presence-group-123',
|
||||
socket_id: '123',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: 'Invalid Pusher resource id, must be a UUID.',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if the passed resource id doesn\'t match the user\'s party', async () => {
|
||||
await expect(user.post(endpoint, {
|
||||
channel_name: `presence-group-${generateUUID()}`,
|
||||
socket_id: '123',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 404,
|
||||
error: 'NotFound',
|
||||
message: 'Resource id must be the user\'s party.',
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -80,7 +80,7 @@ describe('POST /user/auth/social', () => {
|
||||
expect(response.newUser).to.be.false;
|
||||
});
|
||||
|
||||
it('enrolls a new user in an A/B test', async () => {
|
||||
xit('enrolls a new user in an A/B test', async () => {
|
||||
await api.post(endpoint, {
|
||||
authResponse: {access_token: randomAccessToken}, // eslint-disable-line camelcase
|
||||
network,
|
||||
@@ -136,7 +136,7 @@ describe('POST /user/auth/social', () => {
|
||||
expect(response.newUser).to.be.false;
|
||||
});
|
||||
|
||||
it('enrolls a new user in an A/B test', async () => {
|
||||
xit('enrolls a new user in an A/B test', async () => {
|
||||
await api.post(endpoint, {
|
||||
authResponse: {access_token: randomAccessToken}, // eslint-disable-line camelcase
|
||||
network,
|
||||
|
||||
@@ -53,6 +53,6 @@ describe('GET /user', () => {
|
||||
let returnedUser = await user.get('/user');
|
||||
|
||||
expect(returnedUser._id).to.equal(user._id);
|
||||
expect(returnedUser.inbox.messages).to.be.empty;
|
||||
expect(returnedUser.inbox.messages).to.be.undefined;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,12 +2,14 @@ import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import NotificationsComponent from 'client/components/notifications.vue';
|
||||
import Store from 'client/libs/store';
|
||||
import { hasClass } from 'client/store/getters/members';
|
||||
import { toNextLevel } from 'common/script/statHelpers';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Store);
|
||||
|
||||
describe('Notifications', () => {
|
||||
let store;
|
||||
let wrapper;
|
||||
|
||||
beforeEach(() => {
|
||||
store = new Store({
|
||||
@@ -29,16 +31,22 @@ describe('Notifications', () => {
|
||||
actions: {
|
||||
'user:fetch': () => {},
|
||||
'tasks:fetchUserTasks': () => {},
|
||||
'snackbars:add': () => {},
|
||||
},
|
||||
getters: {
|
||||
'members:hasClass': hasClass,
|
||||
},
|
||||
});
|
||||
wrapper = shallowMount(NotificationsComponent, {
|
||||
store,
|
||||
localVue,
|
||||
mocks: {
|
||||
$t: (string) => string,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('set user has class computed prop', () => {
|
||||
const wrapper = shallowMount(NotificationsComponent, { store, localVue });
|
||||
|
||||
expect(wrapper.vm.userHasClass).to.be.false;
|
||||
|
||||
store.state.user.data.stats.lvl = 10;
|
||||
@@ -47,4 +55,130 @@ describe('Notifications', () => {
|
||||
|
||||
expect(wrapper.vm.userHasClass).to.be.true;
|
||||
});
|
||||
describe('user exp notifcation', () => {
|
||||
it('notifies when user gets more exp', () => {
|
||||
const expSpy = sinon.spy(wrapper.vm, 'exp');
|
||||
|
||||
const userLevel = 10;
|
||||
store.state.user.data.stats.lvl = userLevel;
|
||||
|
||||
const userExpBefore = 10;
|
||||
const userExpAfter = 12;
|
||||
wrapper.vm.displayUserExpAndLvlNotifications(userExpAfter, userExpBefore, userLevel, userLevel);
|
||||
|
||||
expect(expSpy).to.be.calledWith(userExpAfter - userExpBefore);
|
||||
expSpy.restore();
|
||||
});
|
||||
|
||||
it('when user levels with exact xp', () => {
|
||||
const expSpy = sinon.spy(wrapper.vm, 'exp');
|
||||
|
||||
const userLevelBefore = 9;
|
||||
const userLevelAfter = 10;
|
||||
store.state.user.data.stats.lvl = userLevelAfter;
|
||||
|
||||
const expEarned = 5;
|
||||
const userExpBefore = toNextLevel(userLevelBefore) - expEarned;
|
||||
const userExpAfter = 0;
|
||||
wrapper.vm.displayUserExpAndLvlNotifications(userExpAfter, userExpBefore, userLevelAfter, userLevelBefore);
|
||||
|
||||
expect(expSpy).to.be.calledWith(expEarned);
|
||||
expSpy.restore();
|
||||
});
|
||||
|
||||
it('when user levels with exact more exp than needed', () => {
|
||||
const expSpy = sinon.spy(wrapper.vm, 'exp');
|
||||
|
||||
const userLevelBefore = 9;
|
||||
const userLevelAfter = 10;
|
||||
store.state.user.data.stats.lvl = userLevelAfter;
|
||||
|
||||
const expEarned = 10;
|
||||
const expNeeded = 5;
|
||||
const userExpBefore = toNextLevel(userLevelBefore) - expNeeded;
|
||||
const userExpAfter = 5;
|
||||
wrapper.vm.displayUserExpAndLvlNotifications(userExpAfter, userExpBefore, userLevelAfter, userLevelBefore);
|
||||
|
||||
expect(expSpy).to.be.calledWith(expEarned);
|
||||
expSpy.restore();
|
||||
});
|
||||
|
||||
it('when user has more exp than needed then levels', () => {
|
||||
const expSpy = sinon.spy(wrapper.vm, 'exp');
|
||||
|
||||
const userLevelBefore = 9;
|
||||
const userLevelAfter = 10;
|
||||
store.state.user.data.stats.lvl = userLevelAfter;
|
||||
|
||||
const expEarned = 10;
|
||||
const expNeeded = -5;
|
||||
const userExpBefore = toNextLevel(userLevelBefore) - expNeeded;
|
||||
const userExpAfter = 15;
|
||||
wrapper.vm.displayUserExpAndLvlNotifications(userExpAfter, userExpBefore, userLevelAfter, userLevelBefore);
|
||||
|
||||
expect(expSpy).to.be.calledWith(expEarned);
|
||||
expSpy.restore();
|
||||
});
|
||||
|
||||
it('when user multilevels', () => {
|
||||
const expSpy = sinon.spy(wrapper.vm, 'exp');
|
||||
|
||||
const userLevelBefore = 8;
|
||||
const userLevelAfter = 10;
|
||||
store.state.user.data.stats.lvl = userLevelAfter;
|
||||
|
||||
const expEarned = 10 + toNextLevel(userLevelBefore + 1);
|
||||
const expNeeded = 5;
|
||||
const userExpBefore = toNextLevel(userLevelBefore) - expNeeded;
|
||||
const userExpAfter = 5;
|
||||
wrapper.vm.displayUserExpAndLvlNotifications(userExpAfter, userExpBefore, userLevelAfter, userLevelBefore);
|
||||
|
||||
expect(expSpy).to.be.calledWith(expEarned);
|
||||
expSpy.restore();
|
||||
});
|
||||
|
||||
it('when user looses xp', () => {
|
||||
const expSpy = sinon.spy(wrapper.vm, 'exp');
|
||||
|
||||
const userLevel = 10;
|
||||
store.state.user.data.stats.lvl = userLevel;
|
||||
|
||||
const userExpBefore = 10;
|
||||
const userExpAfter = 5;
|
||||
wrapper.vm.displayUserExpAndLvlNotifications(userExpAfter, userExpBefore, userLevel, userLevel);
|
||||
|
||||
expect(expSpy).to.be.calledWith(userExpAfter - userExpBefore);
|
||||
expSpy.restore();
|
||||
});
|
||||
|
||||
it('when user looses xp under 0', () => {
|
||||
const expSpy = sinon.spy(wrapper.vm, 'exp');
|
||||
|
||||
const userLevel = 10;
|
||||
store.state.user.data.stats.lvl = userLevel;
|
||||
|
||||
const userExpBefore = 5;
|
||||
const userExpAfter = -3;
|
||||
wrapper.vm.displayUserExpAndLvlNotifications(userExpAfter, userExpBefore, userLevel, userLevel);
|
||||
|
||||
expect(expSpy).to.be.calledWith(userExpAfter - userExpBefore);
|
||||
expSpy.restore();
|
||||
});
|
||||
|
||||
it('when user dies', () => {
|
||||
const expSpy = sinon.spy(wrapper.vm, 'exp');
|
||||
|
||||
const userLevelBefore = 10;
|
||||
const userLevelAfter = 9;
|
||||
store.state.user.data.stats.lvl = userLevelAfter;
|
||||
|
||||
const expEarned = -20;
|
||||
const userExpBefore = 20;
|
||||
const userExpAfter = 0;
|
||||
wrapper.vm.displayUserExpAndLvlNotifications(userExpAfter, userExpBefore, userLevelAfter, userLevelBefore);
|
||||
|
||||
expect(expSpy).to.be.calledWith(expEarned);
|
||||
expSpy.restore();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import armoireSet from '../../../website/common/script/content/gear/sets/armoire';
|
||||
|
||||
describe('armoireSet items', () => {
|
||||
it('checks if canOwn has the same id', () => {
|
||||
for (const type of Object.keys(armoireSet)) {
|
||||
for (const itemKey of Object.keys(armoireSet[type])) {
|
||||
const ownedKey = `${type}_armoire_${itemKey}`;
|
||||
|
||||
expect(armoireSet[type][itemKey].canOwn({
|
||||
items: {
|
||||
gear: {
|
||||
owned: {
|
||||
[ownedKey]: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}), `${ownedKey} canOwn is broken`).to.eq(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -329,23 +329,13 @@ export default {
|
||||
if (notificationNotFoundMessage.indexOf(errorMessage) !== -1) snackbarTimeout = true;
|
||||
|
||||
let errorsToShow = [];
|
||||
let usernameCheck = false;
|
||||
let emailCheck = false;
|
||||
let passwordCheck = false;
|
||||
// show only the first error for each param
|
||||
let paramErrorsFound = {};
|
||||
if (errorData.errors) {
|
||||
for (let e of errorData.errors) {
|
||||
if (!usernameCheck && e.param === 'username') {
|
||||
if (!paramErrorsFound[e.param]) {
|
||||
errorsToShow.push(e.message);
|
||||
usernameCheck = true;
|
||||
}
|
||||
if (!emailCheck && e.param === 'email') {
|
||||
errorsToShow.push(e.message);
|
||||
emailCheck = true;
|
||||
}
|
||||
if (!passwordCheck && e.param === 'password') {
|
||||
errorsToShow.push(e.message);
|
||||
passwordCheck = true;
|
||||
paramErrorsFound[e.param] = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -668,5 +658,6 @@ export default {
|
||||
<style src="assets/css/sprites/spritesmith-main-20.css"></style>
|
||||
<style src="assets/css/sprites/spritesmith-main-21.css"></style>
|
||||
<style src="assets/css/sprites/spritesmith-main-22.css"></style>
|
||||
<style src="assets/css/sprites/spritesmith-main-23.css"></style>
|
||||
<style src="assets/css/sprites.css"></style>
|
||||
<style src="smartbanner.js/dist/smartbanner.min.css"></style>
|
||||
|
||||
@@ -1,84 +1,108 @@
|
||||
.achievement-costumeContest6x {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -1076px -214px;
|
||||
background-position: -1013px -819px;
|
||||
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: -934px -214px;
|
||||
background-position: -1013px -208px;
|
||||
width: 141px;
|
||||
height: 441px;
|
||||
}
|
||||
.promo_armoire_backgrounds_201810 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px -910px;
|
||||
background-position: -848px -1009px;
|
||||
width: 423px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_fall_avatar_customizations {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -1013px 0px;
|
||||
width: 336px;
|
||||
height: 207px;
|
||||
}
|
||||
.promo_fall_festival_2017 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px -699px;
|
||||
background-position: -481px -453px;
|
||||
width: 414px;
|
||||
height: 210px;
|
||||
}
|
||||
.promo_fall_festival_2018 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -934px 0px;
|
||||
background-position: -367px -723px;
|
||||
width: 393px;
|
||||
height: 213px;
|
||||
}
|
||||
.promo_forest_friends_bundle {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -421px -495px;
|
||||
background-position: 0px -1009px;
|
||||
width: 423px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_ghost_potions {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -415px -699px;
|
||||
background-position: -424px -1009px;
|
||||
width: 423px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_ios {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px -337px;
|
||||
background-position: 0px -361px;
|
||||
width: 375px;
|
||||
height: 361px;
|
||||
}
|
||||
.promo_kangaroo {
|
||||
.promo_mystery_201810 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px 0px;
|
||||
width: 420px;
|
||||
height: 336px;
|
||||
}
|
||||
.promo_mystery_201809 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -934px -656px;
|
||||
width: 306px;
|
||||
height: 147px;
|
||||
background-position: -1013px -650px;
|
||||
width: 294px;
|
||||
height: 168px;
|
||||
}
|
||||
.promo_seasonal_shop {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -1076px -371px;
|
||||
background-position: -1155px -503px;
|
||||
width: 162px;
|
||||
height: 138px;
|
||||
}
|
||||
.promo_spooky_sparkles {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -1155px -208px;
|
||||
width: 140px;
|
||||
height: 294px;
|
||||
}
|
||||
.promo_take_this {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -1221px -214px;
|
||||
background-position: -1158px -819px;
|
||||
width: 96px;
|
||||
height: 69px;
|
||||
}
|
||||
.promo_veteran_pets {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px -1157px;
|
||||
width: 363px;
|
||||
height: 141px;
|
||||
}
|
||||
.scene_nametag {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -421px 0px;
|
||||
background-position: -481px -244px;
|
||||
width: 512px;
|
||||
height: 208px;
|
||||
}
|
||||
.scene_positivity {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -481px 0px;
|
||||
width: 531px;
|
||||
height: 243px;
|
||||
}
|
||||
.scene_tools {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -421px -209px;
|
||||
background-position: 0px -723px;
|
||||
width: 366px;
|
||||
height: 285px;
|
||||
}
|
||||
|
||||
@@ -1,42 +1,54 @@
|
||||
.quest_TEMPLATE_FOR_MISSING_IMAGE {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -719px -1546px;
|
||||
background-position: -502px -1546px;
|
||||
width: 221px;
|
||||
height: 39px;
|
||||
}
|
||||
.quest_dustbunnies {
|
||||
.quest_dilatoryDistress2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -220px -452px;
|
||||
background-position: -1757px -1023px;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.quest_dilatoryDistress3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1320px -660px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_egg {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -537px;
|
||||
width: 165px;
|
||||
height: 207px;
|
||||
}
|
||||
.quest_evilsanta {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -1198px;
|
||||
width: 118px;
|
||||
height: 131px;
|
||||
}
|
||||
.quest_evilsanta2 {
|
||||
.quest_dustbunnies {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -440px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_egg {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -362px;
|
||||
width: 165px;
|
||||
height: 207px;
|
||||
}
|
||||
.quest_evilsanta {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -1174px;
|
||||
width: 118px;
|
||||
height: 131px;
|
||||
}
|
||||
.quest_evilsanta2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -440px -232px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_falcon {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -232px;
|
||||
background-position: -660px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_ferret {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -220px -232px;
|
||||
background-position: -660px -220px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
@@ -48,19 +60,19 @@
|
||||
}
|
||||
.quest_ghost_stag {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -660px 0px;
|
||||
background-position: -220px -452px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_goldenknight1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -660px -220px;
|
||||
background-position: -440px -452px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_goldenknight2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -217px -1546px;
|
||||
background-position: 0px -1546px;
|
||||
width: 250px;
|
||||
height: 150px;
|
||||
}
|
||||
@@ -72,19 +84,19 @@
|
||||
}
|
||||
.quest_gryphon {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1314px -1332px;
|
||||
background-position: -1097px -1332px;
|
||||
width: 216px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_guineapig {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -660px -452px;
|
||||
background-position: -880px -440px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_harpy {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -880px 0px;
|
||||
background-position: 0px -672px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
@@ -96,19 +108,19 @@
|
||||
}
|
||||
.quest_hippo {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -880px -440px;
|
||||
background-position: -440px -672px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_horse {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -672px;
|
||||
background-position: -660px -672px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_kangaroo {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -220px -672px;
|
||||
background-position: -880px -672px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
@@ -120,73 +132,73 @@
|
||||
}
|
||||
.quest_lostMasterclasser1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -660px -672px;
|
||||
background-position: -1100px -220px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_lostMasterclasser2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -880px -672px;
|
||||
background-position: -1100px -440px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_lostMasterclasser3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1100px 0px;
|
||||
background-position: -1100px -660px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_mayhemMistiflying1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -1047px;
|
||||
background-position: -1757px -872px;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.quest_mayhemMistiflying2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1100px -440px;
|
||||
background-position: -220px -892px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_mayhemMistiflying3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1100px -660px;
|
||||
background-position: -440px -892px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_monkey {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -892px;
|
||||
background-position: -660px -892px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_moon1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1540px -651px;
|
||||
background-position: -1540px -434px;
|
||||
width: 216px;
|
||||
height: 216px;
|
||||
}
|
||||
.quest_moon2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -440px -892px;
|
||||
background-position: -1100px -892px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_moon3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -660px -892px;
|
||||
background-position: -1320px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_moonstone1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -880px -892px;
|
||||
background-position: -1320px -220px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_moonstone2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1100px -892px;
|
||||
background-position: -1320px -440px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
@@ -198,7 +210,7 @@
|
||||
}
|
||||
.quest_nudibranch {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1540px 0px;
|
||||
background-position: -1540px -217px;
|
||||
width: 216px;
|
||||
height: 216px;
|
||||
}
|
||||
@@ -210,49 +222,49 @@
|
||||
}
|
||||
.quest_owl {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1320px -660px;
|
||||
background-position: -220px -1112px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_peacock {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1540px -217px;
|
||||
background-position: -1540px 0px;
|
||||
width: 216px;
|
||||
height: 216px;
|
||||
}
|
||||
.quest_penguin {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -353px;
|
||||
background-position: -1757px -178px;
|
||||
width: 190px;
|
||||
height: 183px;
|
||||
}
|
||||
.quest_pterodactyl {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -220px -1112px;
|
||||
background-position: -880px -1112px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_rat {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -440px -1112px;
|
||||
background-position: -660px -1112px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_rock {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1540px -868px;
|
||||
background-position: -1540px -651px;
|
||||
width: 216px;
|
||||
height: 216px;
|
||||
}
|
||||
.quest_rooster {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px 0px;
|
||||
background-position: -1531px -1332px;
|
||||
width: 213px;
|
||||
height: 174px;
|
||||
}
|
||||
.quest_sabretooth {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -660px -1112px;
|
||||
background-position: -440px -1112px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
@@ -270,13 +282,13 @@
|
||||
}
|
||||
.quest_slime {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1320px -440px;
|
||||
background-position: -880px -892px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_sloth {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1320px -220px;
|
||||
background-position: 0px -892px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
@@ -288,31 +300,31 @@
|
||||
}
|
||||
.quest_snake {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1097px -1332px;
|
||||
background-position: -1314px -1332px;
|
||||
width: 216px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_spider {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -468px -1546px;
|
||||
background-position: -251px -1546px;
|
||||
width: 250px;
|
||||
height: 150px;
|
||||
}
|
||||
.quest_squirrel {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1320px 0px;
|
||||
background-position: -1100px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_stoikalmCalamity1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -896px;
|
||||
background-position: -1757px -721px;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.quest_stoikalmCalamity2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -440px -672px;
|
||||
background-position: -220px -672px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
@@ -324,109 +336,67 @@
|
||||
}
|
||||
.quest_taskwoodsTerror1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -745px;
|
||||
background-position: -1757px -570px;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
.quest_taskwoodsTerror2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1540px -1085px;
|
||||
background-position: -1540px -868px;
|
||||
width: 216px;
|
||||
height: 216px;
|
||||
}
|
||||
.quest_taskwoodsTerror3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -440px -452px;
|
||||
background-position: -660px -452px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_treeling {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -1546px;
|
||||
background-position: -880px -1332px;
|
||||
width: 216px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_trex {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1757px -175px;
|
||||
background-position: -1757px 0px;
|
||||
width: 204px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_trex_undead {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1531px -1332px;
|
||||
background-position: -1540px -1085px;
|
||||
width: 216px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_triceratops {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -440px -232px;
|
||||
background-position: 0px -452px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_turtle {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -880px -1112px;
|
||||
background-position: -220px -232px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_unicorn {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: 0px -452px;
|
||||
background-position: 0px -232px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_vice1 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -880px -1332px;
|
||||
background-position: -663px -1332px;
|
||||
width: 216px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_vice2 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -220px -892px;
|
||||
background-position: -880px 0px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_vice3 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -663px -1332px;
|
||||
width: 216px;
|
||||
height: 177px;
|
||||
}
|
||||
.quest_whale {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1100px -220px;
|
||||
width: 219px;
|
||||
height: 219px;
|
||||
}
|
||||
.quest_yarn {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1540px -434px;
|
||||
width: 216px;
|
||||
height: 216px;
|
||||
}
|
||||
.quest_atom1_soapBars {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1908px -745px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
.quest_dilatoryDistress1_blueFins {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1908px -797px;
|
||||
width: 51px;
|
||||
height: 48px;
|
||||
}
|
||||
.quest_dilatoryDistress1_fireCoral {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1908px -896px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
.quest_egg_plainEgg {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-11.png');
|
||||
background-position: -1908px -948px;
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
}
|
||||
|
||||
@@ -1,114 +1,522 @@
|
||||
.Pet-Turtle-Skeleton {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -82px 0px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Turtle-White {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -246px -500px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Turtle-Zombie {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -164px 0px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Unicorn-Base {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: 0px -100px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Unicorn-CottonCandyBlue {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -82px -100px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Unicorn-CottonCandyPink {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -164px -100px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Unicorn-Desert {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -246px 0px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Unicorn-Golden {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -246px -100px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Unicorn-Red {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: 0px -200px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Unicorn-Shade {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -82px -200px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Unicorn-Skeleton {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -164px -200px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Unicorn-White {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -246px -200px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Unicorn-Zombie {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -328px 0px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Whale-Base {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -328px -100px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Whale-CottonCandyBlue {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -328px -200px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Whale-CottonCandyPink {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: 0px -300px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Whale-Desert {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -82px -300px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Whale-Golden {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -164px -300px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Whale-Red {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -246px -300px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Whale-Shade {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -328px -300px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Whale-Skeleton {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -410px 0px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Whale-White {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -410px -100px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Whale-Zombie {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -410px -200px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Aquatic {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -410px -300px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Base {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -492px 0px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-CottonCandyBlue {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -492px -100px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-CottonCandyPink {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -492px -200px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Cupid {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -492px -300px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Desert {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: 0px -400px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Ember {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -82px -400px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Fairy {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -164px -400px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Floral {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -246px -400px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Ghost {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -328px -400px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Glass {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -410px -400px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Glow {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -492px -400px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Golden {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -574px 0px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Holly {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -574px -100px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Peppermint {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -574px -200px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Rainbow {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -574px -300px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Red {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -574px -400px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-RoyalPurple {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: 0px -500px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Shade {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -82px -500px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Shimmer {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -164px -500px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Skeleton {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: 0px 0px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Spooky {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -328px -500px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-StarryNight {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -410px -500px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Thunderstorm {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -492px -500px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Veteran {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -574px -500px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-White {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -656px 0px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Wolf-Zombie {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -656px -100px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Yarn-Base {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -656px -200px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Yarn-CottonCandyBlue {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -656px -300px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Yarn-CottonCandyPink {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -656px -400px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Yarn-Desert {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -656px -500px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Yarn-Golden {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: 0px -600px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Yarn-Red {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -82px -600px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Yarn-Shade {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -164px -600px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Yarn-Skeleton {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -246px -600px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Yarn-White {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -328px -600px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet-Yarn-Zombie {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -410px -600px;
|
||||
width: 81px;
|
||||
height: 99px;
|
||||
}
|
||||
.Pet_HatchingPotion_Aquatic {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -561px -600px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_Base {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: 0px -700px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_CottonCandyBlue {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -630px -600px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_CottonCandyPink {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -738px 0px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_Cupid {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -738px -69px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_Desert {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -738px -138px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_Ember {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -738px -207px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_Fairy {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -738px -276px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_Floral {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -69px 0px;
|
||||
background-position: -738px -345px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_Ghost {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -207px 0px;
|
||||
background-position: -738px -414px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_Glass {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: 0px -69px;
|
||||
background-position: -738px -483px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_Glow {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -69px -69px;
|
||||
background-position: -738px -552px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_Golden {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -138px 0px;
|
||||
background-position: -738px -621px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_Holly {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -138px -69px;
|
||||
background-position: -492px -600px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_Peppermint {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: 0px -138px;
|
||||
background-position: -69px -700px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_Purple {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -69px -138px;
|
||||
background-position: -138px -700px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_Rainbow {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -138px -138px;
|
||||
background-position: -207px -700px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_Red {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: 0px 0px;
|
||||
background-position: -276px -700px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_RoyalPurple {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -207px -69px;
|
||||
background-position: -345px -700px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_Shade {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -207px -138px;
|
||||
background-position: -414px -700px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_Shimmer {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: 0px -207px;
|
||||
background-position: -483px -700px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_Skeleton {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -69px -207px;
|
||||
background-position: -552px -700px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_Spooky {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -138px -207px;
|
||||
background-position: -621px -700px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_StarryNight {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -207px -207px;
|
||||
background-position: -690px -700px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_Thunderstorm {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -276px 0px;
|
||||
background-position: -807px 0px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_White {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -276px -69px;
|
||||
background-position: -807px -69px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.Pet_HatchingPotion_Zombie {
|
||||
background-image: url('~assets/images/sprites/spritesmith-main-23.png');
|
||||
background-position: -276px -138px;
|
||||
background-position: -807px -138px;
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 177 KiB After Width: | Height: | Size: 256 KiB |
|
Before Width: | Height: | Size: 181 KiB After Width: | Height: | Size: 178 KiB |
|
Before Width: | Height: | Size: 419 KiB After Width: | Height: | Size: 418 KiB |
|
Before Width: | Height: | Size: 192 KiB After Width: | Height: | Size: 202 KiB |
|
Before Width: | Height: | Size: 157 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 146 KiB After Width: | Height: | Size: 144 KiB |
|
Before Width: | Height: | Size: 135 KiB After Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 156 KiB After Width: | Height: | Size: 165 KiB |
|
Before Width: | Height: | Size: 148 KiB After Width: | Height: | Size: 145 KiB |
|
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 144 KiB |
|
Before Width: | Height: | Size: 147 KiB After Width: | Height: | Size: 151 KiB |
|
Before Width: | Height: | Size: 178 KiB After Width: | Height: | Size: 174 KiB |
|
Before Width: | Height: | Size: 159 KiB After Width: | Height: | Size: 161 KiB |
|
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 164 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 130 KiB |
|
Before Width: | Height: | Size: 114 KiB After Width: | Height: | Size: 115 KiB |
@@ -243,7 +243,7 @@
|
||||
&-control {
|
||||
&-bg {
|
||||
background: rgba(255, 217, 160, 0.32) !important;
|
||||
.small-text { color: $yellow-10 !important; }
|
||||
.small-text { color: $orange-10 !important; }
|
||||
|
||||
&:hover { background: rgba(255, 217, 160, 0.48) !important; }
|
||||
}
|
||||
|
||||
@@ -40,9 +40,9 @@
|
||||
import axios from 'axios';
|
||||
import Avatar from '../avatar';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import revive from '../../../common/script/ops/revive';
|
||||
import percent from '../../../common/script/libs/percent';
|
||||
import {maxHealth} from '../../../common/script/index';
|
||||
import revive from '../../../common/script/ops/revive';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template lang="pug">
|
||||
b-modal#rebirth(:title="$t('modalAchievement')", size='md', :hide-footer="true")
|
||||
b-modal#rebirth(:title="$t('modalAchievement')", size='md', :hide-footer="true", @hidden="reloadPage()")
|
||||
.modal-body
|
||||
.col-12
|
||||
// @TODO: +achievementAvatar('sun',0)
|
||||
@@ -24,23 +24,26 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import achievementFooter from './achievementFooter';
|
||||
import achievementAvatar from './achievementAvatar';
|
||||
import achievementFooter from './achievementFooter';
|
||||
import achievementAvatar from './achievementAvatar';
|
||||
|
||||
import { mapState } from 'client/libs/store';
|
||||
import {mapState} from 'client/libs/store';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
achievementFooter,
|
||||
achievementAvatar,
|
||||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
},
|
||||
methods: {
|
||||
close () {
|
||||
this.$root.$emit('bv::hide::modal', 'rebirth');
|
||||
export default {
|
||||
components: {
|
||||
achievementFooter,
|
||||
achievementAvatar,
|
||||
},
|
||||
},
|
||||
};
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
},
|
||||
methods: {
|
||||
close () {
|
||||
this.$root.$emit('bv::hide::modal', 'rebirth');
|
||||
},
|
||||
reloadPage () {
|
||||
window.location.reload(true);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -14,11 +14,17 @@
|
||||
button.btn.btn-secondary.create-challenge-button.float-right(@click='createChallenge()')
|
||||
.svg-icon.positive-icon(v-html="icons.positiveIcon")
|
||||
span(v-once) {{$t('createChallenge')}}
|
||||
|
||||
.row
|
||||
.no-challenges.text-center.col-md-6.offset-3(v-if='!loading && filteredChallenges.length === 0')
|
||||
h2(v-once) {{$t('noChallengeMatchFilters')}}
|
||||
|
||||
.row
|
||||
.col-12.col-md-6(v-for='challenge in filteredChallenges')
|
||||
challenge-item(:challenge='challenge')
|
||||
|
||||
.row
|
||||
.col-12.text-center
|
||||
.col-12.text-center(v-if='!loading && filteredChallenges.length > 0')
|
||||
button.btn.btn-secondary(@click='loadMore()') {{ $t('loadMore') }}
|
||||
</template>
|
||||
|
||||
@@ -41,6 +47,15 @@
|
||||
margin-right: .5em;
|
||||
}
|
||||
}
|
||||
|
||||
.no-challenges {
|
||||
color: $gray-200;
|
||||
margin-top: 10em;
|
||||
|
||||
h2 {
|
||||
color: $gray-200;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
.row.header-row
|
||||
.col-md-8.text-left
|
||||
h1(v-once) {{$t('myChallenges')}}
|
||||
h2(v-if='loading && challenges.length === 0') {{ $t('loading') }}
|
||||
.col-md-4
|
||||
// @TODO: implement sorting span.dropdown-label {{ $t('sortBy') }}
|
||||
b-dropdown(:text="$t('sort')", right=true)
|
||||
@@ -16,12 +17,16 @@
|
||||
span(v-once) {{$t('createChallenge')}}
|
||||
|
||||
.row
|
||||
.no-challenges.text-center.col-md-6.offset-3(v-if='filteredChallenges.length === 0')
|
||||
.no-challenges.text-center.col-md-6.offset-3(v-if='!loading && challenges.length === 0')
|
||||
.svg-icon(v-html="icons.challengeIcon")
|
||||
h2(v-once) {{$t('noChallengeTitle')}}
|
||||
p(v-once) {{$t('challengeDescription1')}}
|
||||
p(v-once) {{$t('challengeDescription2')}}
|
||||
|
||||
.row
|
||||
.no-challenges.text-center.col-md-6.offset-3(v-if='!loading && challenges.length > 0 && filteredChallenges.length === 0')
|
||||
h2(v-once) {{$t('noChallengeMatchFilters')}}
|
||||
|
||||
.row
|
||||
.col-12.col-md-6(v-for='challenge in filteredChallenges')
|
||||
challenge-item(:challenge='challenge')
|
||||
@@ -48,14 +53,15 @@
|
||||
}
|
||||
|
||||
.no-challenges {
|
||||
color: $gray-300;
|
||||
color: $gray-200;
|
||||
margin-top: 10em;
|
||||
|
||||
h2 {
|
||||
color: $gray-300;
|
||||
color: $gray-200;
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
color: #C3C0C7;
|
||||
width: 88.7px;
|
||||
margin: 1em auto;
|
||||
}
|
||||
@@ -84,6 +90,7 @@ export default {
|
||||
challengeIcon,
|
||||
positiveIcon,
|
||||
}),
|
||||
loading: false,
|
||||
challenges: [],
|
||||
sort: 'none',
|
||||
sortOptions: [
|
||||
@@ -113,7 +120,7 @@ export default {
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
this.loadchallanges();
|
||||
this.loadChallenges();
|
||||
},
|
||||
computed: {
|
||||
filteredChallenges () {
|
||||
@@ -138,10 +145,12 @@ export default {
|
||||
this.$store.state.challengeOptions.workingChallenge = {};
|
||||
this.$root.$emit('bv::show::modal', 'challenge-modal');
|
||||
},
|
||||
async loadchallanges () {
|
||||
async loadChallenges () {
|
||||
this.loading = true;
|
||||
this.challenges = await this.$store.dispatch('challenges:getUserChallenges', {
|
||||
member: true,
|
||||
});
|
||||
this.loading = false;
|
||||
},
|
||||
challengeCreated (challenge) {
|
||||
this.challenges.push(challenge);
|
||||
|
||||
@@ -14,7 +14,7 @@ div.autocomplete-selection(v-if='searchResults.length > 0', :style='autocomplete
|
||||
import groupBy from 'lodash/groupBy';
|
||||
|
||||
export default {
|
||||
props: ['selections', 'text', 'coords', 'chat'],
|
||||
props: ['selections', 'text', 'coords', 'chat', 'textbox'],
|
||||
data () {
|
||||
return {
|
||||
currentSearch: '',
|
||||
@@ -25,9 +25,15 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
autocompleteStyle () {
|
||||
function heightToUse (textBox, topCoords) {
|
||||
let textBoxHeight = textBox['user-entry'].clientHeight;
|
||||
return topCoords < textBoxHeight ? topCoords + 30 : textBoxHeight + 10;
|
||||
}
|
||||
return {
|
||||
top: `${this.coords.TOP + 30}px`,
|
||||
top: `${heightToUse(this.textbox, this.coords.TOP)}px`,
|
||||
left: `${this.coords.LEFT + 30}px`,
|
||||
marginLeft: '-28px',
|
||||
marginTop: '28px',
|
||||
position: 'absolute',
|
||||
minWidth: '100px',
|
||||
minHeight: '100px',
|
||||
@@ -42,6 +48,7 @@ export default {
|
||||
return option.toLowerCase().indexOf(currentSearch.toLowerCase()) !== -1;
|
||||
});
|
||||
},
|
||||
|
||||
},
|
||||
mounted () {
|
||||
this.grabUserNames();
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
.row
|
||||
textarea(:placeholder='placeholder',
|
||||
v-model='newMessage',
|
||||
ref='user-entry',
|
||||
:class='{"user-entry": newMessage}',
|
||||
@keydown='updateCarretPosition',
|
||||
@keyup.ctrl.enter='sendMessageShortcut()',
|
||||
@@ -16,6 +17,7 @@
|
||||
autocomplete(
|
||||
:text='newMessage',
|
||||
v-on:select="selectedAutocomplete",
|
||||
:textbox='textbox',
|
||||
:coords='coords',
|
||||
:chat='group.chat')
|
||||
|
||||
@@ -62,6 +64,7 @@
|
||||
TOP: 0,
|
||||
LEFT: 0,
|
||||
},
|
||||
textbox: this.$refs,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -187,7 +190,7 @@
|
||||
position: relative;
|
||||
|
||||
textarea {
|
||||
height: 150px;
|
||||
min-height: 150px;
|
||||
width: 100%;
|
||||
background-color: $white;
|
||||
border: solid 1px $gray-400;
|
||||
|
||||
@@ -14,6 +14,11 @@
|
||||
button.btn.btn-secondary.create-group-button.float-right(@click='createGroup()')
|
||||
.svg-icon.positive-icon(v-html="icons.positiveIcon")
|
||||
span(v-once) {{$t('createGuild2')}}
|
||||
|
||||
.row
|
||||
.no-guilds.text-center.col-md-6.offset-md-3(v-if='!loading && filteredGuilds.length === 0')
|
||||
h2(v-once) {{$t('noGuildsMatchFilters')}}
|
||||
|
||||
.row
|
||||
.col-md-12
|
||||
public-guild-item(v-for="guild in filteredGuilds", :key='guild._id', :guild="guild", :display-leave='true')
|
||||
@@ -39,6 +44,15 @@
|
||||
display: inline-block;
|
||||
margin-right: .5em;
|
||||
}
|
||||
|
||||
.no-guilds {
|
||||
color: $gray-200;
|
||||
margin-top: 10em;
|
||||
|
||||
h2 {
|
||||
color: $gray-200;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -5,7 +5,8 @@ div
|
||||
.header
|
||||
h1.text-center Need more for your Group?
|
||||
.row
|
||||
.col-6.offset-3.text-center {{ $t('groupBenefitsDescription') }}
|
||||
.col-8.offset-2.text-center
|
||||
h2.sub-text {{ $t('groupBenefitsDescription') }}
|
||||
.container.benefits
|
||||
.row
|
||||
.col-4
|
||||
@@ -165,23 +166,32 @@ div
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-bottom: 3em;
|
||||
margin-top: 4em;
|
||||
background-color: #4f2a93;
|
||||
background: #432874;
|
||||
background: linear-gradient(180deg, #4F2A93 0%, #432874 100%);
|
||||
color: #fff;
|
||||
padding: 2em;
|
||||
height: 356px;
|
||||
height: 340px;
|
||||
margin-bottom: 2em;
|
||||
margin-left: -12px;
|
||||
margin-right: -12px;
|
||||
|
||||
h1 {
|
||||
font-size: 48px;
|
||||
line-height: 1.16;
|
||||
margin-top: 12px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
h2.sub-text {
|
||||
color: #D5C8FF;
|
||||
font-size: 24px;
|
||||
font-weight: 400;
|
||||
line-height: 1.33;
|
||||
}
|
||||
}
|
||||
|
||||
.benefits {
|
||||
margin-top: -12em;
|
||||
margin-top: -10em;
|
||||
|
||||
.box {
|
||||
height: 416px;
|
||||
|
||||
@@ -33,29 +33,29 @@ div
|
||||
.col-1.actions
|
||||
b-dropdown(right=true)
|
||||
.svg-icon.inline.dots(slot='button-content', v-html="icons.dots")
|
||||
b-dropdown-item(@click='removeMember(member, index)', v-if='isLeader')
|
||||
span.dropdown-icon-item
|
||||
.svg-icon.inline(v-html="icons.removeIcon", v-if='isLeader')
|
||||
span.text {{$t('removeMember')}}
|
||||
b-dropdown-item(@click='sendMessage(member)')
|
||||
span.dropdown-icon-item
|
||||
.svg-icon.inline(v-html="icons.messageIcon")
|
||||
span.text {{$t('sendMessage')}}
|
||||
b-dropdown-item(@click='promoteToLeader(member)', v-if='shouldShowPromoteToLeader')
|
||||
b-dropdown-item(@click='promoteToLeader(member)', v-if='shouldShowLeaderFunctions(member._id)')
|
||||
span.dropdown-icon-item
|
||||
.svg-icon.inline(v-html="icons.starIcon")
|
||||
span.text {{$t('promoteToLeader')}}
|
||||
b-dropdown-item(@click='addManager(member._id)', v-if='isLeader && groupIsSubscribed')
|
||||
b-dropdown-item(@click='addManager(member._id)', v-if='shouldShowAddManager(member._id)')
|
||||
span.dropdown-icon-item
|
||||
.svg-icon.inline(v-html="icons.starIcon")
|
||||
span.text {{$t('addManager')}}
|
||||
b-dropdown-item(@click='removeManager(member._id)', v-if='isLeader && groupIsSubscribed')
|
||||
b-dropdown-item(@click='removeManager(member._id)', v-if='shouldShowRemoveManager(member._id)')
|
||||
span.dropdown-icon-item
|
||||
.svg-icon.inline(v-html="icons.removeIcon")
|
||||
span.text {{$t('removeManager2')}}
|
||||
b-dropdown-item(@click='viewProgress(member)', v-if='challengeId')
|
||||
span.dropdown-icon-item
|
||||
span.text {{ $t('viewProgress') }}
|
||||
b-dropdown-item(@click='removeMember(member, index)', v-if='shouldShowLeaderFunctions(member._id)')
|
||||
span.dropdown-icon-item
|
||||
.svg-icon.inline(v-html="icons.removeIcon")
|
||||
span.text {{$t('removeMember')}}
|
||||
.row(v-if='isLoadMoreAvailable')
|
||||
.col-12.text-center
|
||||
button.btn.btn-secondary(@click='loadMoreMembers()') {{ $t('loadMore') }}
|
||||
@@ -295,9 +295,6 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
shouldShowPromoteToLeader () {
|
||||
return !this.challengeId && (this.isLeader || this.isAdmin);
|
||||
},
|
||||
isLeader () {
|
||||
if (!this.group || !this.group.leader) return false;
|
||||
return this.user._id === this.group.leader || this.user._id === this.group.leader._id;
|
||||
@@ -498,6 +495,18 @@ export default {
|
||||
progressMemberId: member._id,
|
||||
});
|
||||
},
|
||||
shouldShowAddManager (memberId) {
|
||||
if (!this.isLeader && !this.isAdmin) return false;
|
||||
if (memberId === this.group.leader || memberId === this.group.leader._id) return false;
|
||||
return this.groupIsSubscribed && !(this.group.managers && this.group.managers[memberId]);
|
||||
},
|
||||
shouldShowRemoveManager (memberId) {
|
||||
if (!this.isLeader && !this.isAdmin) return false;
|
||||
return this.group.managers && this.group.managers[memberId];
|
||||
},
|
||||
shouldShowLeaderFunctions (memberId) {
|
||||
return !this.challengeId && (this.isLeader || this.isAdmin) && this.user._id !== memberId;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -2,18 +2,11 @@
|
||||
.row
|
||||
sidebar(v-on:search="updateSearch", v-on:filter="updateFilters")
|
||||
|
||||
.no-guilds.standard-page(v-if='filteredGuilds.length === 0')
|
||||
.no-guilds-wrapper
|
||||
.svg-icon(v-html='icons.greyBadge')
|
||||
h2 {{$t('noGuildsTitle')}}
|
||||
p {{$t('noGuildsParagraph1')}}
|
||||
p {{$t('noGuildsParagraph2')}}
|
||||
span(v-if='loading') {{ $t('loading') }}
|
||||
|
||||
.standard-page(v-if='filteredGuilds.length > 0')
|
||||
.standard-page
|
||||
.row
|
||||
.col-md-8
|
||||
h1.page-header.float-left(v-once) {{ $t('myGuilds') }}
|
||||
.col-md-8.text-left
|
||||
h1.page-header(v-once) {{ $t('myGuilds') }}
|
||||
h2(v-if='loading && guilds.length === 0') {{ $t('loading') }}
|
||||
.col-4
|
||||
button.btn.btn-secondary.create-group-button.float-right(@click='createGroup()')
|
||||
.svg-icon.positive-icon(v-html="icons.positiveIcon")
|
||||
@@ -22,6 +15,18 @@
|
||||
span.dropdown-label {{ $t('sortBy') }}
|
||||
b-dropdown(:text="$t('sort')", right=true)
|
||||
b-dropdown-item(v-for='sortOption in sortOptions', :key="sortOption.value", @click='sort(sortOption.value)') {{sortOption.text}}
|
||||
|
||||
.row
|
||||
.no-guilds.text-center.col-md-6.offset-md-3(v-if='!loading && guilds.length === 0')
|
||||
.svg-icon(v-html='icons.greyBadge')
|
||||
h2(v-once) {{$t('noGuildsTitle')}}
|
||||
p(v-once) {{$t('noGuildsParagraph1')}}
|
||||
p(v-once) {{$t('noGuildsParagraph2')}}
|
||||
|
||||
.row
|
||||
.no-guilds.text-center.col-md-6.offset-md-3(v-if='!loading && guilds.length > 0 && filteredGuilds.length === 0')
|
||||
h2(v-once) {{$t('noGuildsMatchFilters')}}
|
||||
|
||||
.row
|
||||
.col-md-12
|
||||
public-guild-item(v-for="guild in filteredGuilds", :key='guild._id', :guild="guild", :display-gem-bank='true')
|
||||
@@ -41,29 +46,16 @@
|
||||
}
|
||||
|
||||
.no-guilds {
|
||||
text-align: center;
|
||||
color: $gray-200;
|
||||
margin-top: 15em;
|
||||
margin-top: 10em;
|
||||
|
||||
p {
|
||||
font-size: 14px;
|
||||
line-height: 1.43;
|
||||
h2 {
|
||||
color: $gray-200;
|
||||
}
|
||||
|
||||
.no-guilds-wrapper {
|
||||
width: 400px;
|
||||
margin: 0 auto;
|
||||
|
||||
.svg-icon {
|
||||
width: 60px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
.no-guilds-wrapper {
|
||||
width: 100% !important;
|
||||
.svg-icon {
|
||||
width: 88.7px;
|
||||
margin: 1em auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -139,8 +139,6 @@ export default {
|
||||
this.emitFilters();
|
||||
},
|
||||
searchTerm: throttle(function searchTerm (newSearch) {
|
||||
if (newSearch.length <= 1) return; // @TODO: eh, should we limit based on length?
|
||||
|
||||
this.$emit('search', {
|
||||
searchTerm: newSearch,
|
||||
});
|
||||
|
||||
@@ -154,11 +154,13 @@ export default {
|
||||
this.$root.$emit('bv::show::modal', 'create-party-modal');
|
||||
}
|
||||
},
|
||||
showPartyMembers () {
|
||||
async showPartyMembers () {
|
||||
const party = await this.$store.dispatch('party:getParty');
|
||||
|
||||
this.$root.$emit('habitica:show-member-modal', {
|
||||
groupId: this.user.party._id,
|
||||
groupId: party.data._id,
|
||||
viewingMembers: this.partyMembers,
|
||||
group: this.user.party,
|
||||
group: party.data,
|
||||
});
|
||||
},
|
||||
setPartyMembersWidth ($event) {
|
||||
|
||||
@@ -87,7 +87,9 @@ div
|
||||
import axios from 'axios';
|
||||
import moment from 'moment';
|
||||
import throttle from 'lodash/throttle';
|
||||
import debounce from 'lodash/debounce';
|
||||
|
||||
import { toNextLevel } from '../../common/script/statHelpers';
|
||||
import { shouldDo } from '../../common/script/cron';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import notifications from 'client/mixins/notifications';
|
||||
@@ -117,6 +119,39 @@ import ultimateGear from './achievements/ultimateGear';
|
||||
import wonChallenge from './achievements/wonChallenge';
|
||||
import loginIncentives from './achievements/login-incentives';
|
||||
|
||||
const NOTIFICATIONS = {
|
||||
CHALLENGE_JOINED_ACHIEVEMENT: {
|
||||
achievement: true,
|
||||
label: ($t) => `${$t('achievement')}: ${$t('joinedChallenge')}`,
|
||||
modalId: 'joined-challenge',
|
||||
},
|
||||
ULTIMATE_GEAR_ACHIEVEMENT: {
|
||||
achievement: true,
|
||||
label: ($t) => `${$t('achievement')}: ${$t('gearAchievementNotification')}`,
|
||||
modalId: 'ultimate-gear',
|
||||
},
|
||||
REBIRTH_ACHIEVEMENT: {
|
||||
label: ($t) => `${$t('achievement')}: ${$t('rebirthBegan')}`,
|
||||
achievement: true,
|
||||
modalId: 'rebirth',
|
||||
},
|
||||
GUILD_JOINED_ACHIEVEMENT: {
|
||||
label: ($t) => `${$t('achievement')}: ${$t('joinedGuild')}`,
|
||||
achievement: true,
|
||||
modalId: 'joined-guild',
|
||||
},
|
||||
INVITED_FRIEND_ACHIEVEMENT: {
|
||||
achievement: true,
|
||||
label: ($t) => `${$t('achievement')}: ${$t('invitedFriend')}`,
|
||||
modalId: 'invited-friend',
|
||||
},
|
||||
NEW_CONTRIBUTOR_LEVEL: {
|
||||
achievement: true,
|
||||
label: ($t) => $t('modalContribAchievement'),
|
||||
modalId: 'contributor',
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
mixins: [notifications, guide],
|
||||
components: {
|
||||
@@ -186,10 +221,8 @@ export default {
|
||||
...mapState({
|
||||
user: 'user.data',
|
||||
userHp: 'user.data.stats.hp',
|
||||
userExp: 'user.data.stats.exp',
|
||||
userGp: 'user.data.stats.gp',
|
||||
userMp: 'user.data.stats.mp',
|
||||
userLvl: 'user.data.stats.lvl',
|
||||
userNotifications: 'user.data.notifications',
|
||||
userAchievements: 'user.data.achievements', // @TODO: does this watch deeply?
|
||||
armoireEmpty: 'user.data.flags.armoireEmpty',
|
||||
@@ -204,13 +237,15 @@ export default {
|
||||
invitedToQuest () {
|
||||
return this.user.party.quest.RSVPNeeded && !this.user.party.quest.completed;
|
||||
},
|
||||
userExpAndLvl () {
|
||||
return [this.user.stats.exp, this.user.stats.lvl];
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
userHp (after, before) {
|
||||
if (this.user.needsCron) return;
|
||||
if (after <= 0) {
|
||||
this.playSound('Death');
|
||||
this.$root.$emit('bv::show::modal', 'death');
|
||||
this.showDeathModal();
|
||||
// @TODO: {keyboard:false, backdrop:'static'}
|
||||
} else if (after <= 30 && !this.user.flags.warnedLowHealth) {
|
||||
this.$root.$emit('bv::show::modal', 'low-health');
|
||||
@@ -222,11 +257,6 @@ export default {
|
||||
|
||||
if (after < 0) this.playSound('Minus_Habit');
|
||||
},
|
||||
userExp (after, before) {
|
||||
if (after === before) return;
|
||||
if (this.user.stats.lvl === 0) return;
|
||||
this.exp(after - before);
|
||||
},
|
||||
userGp (after, before) {
|
||||
if (after === before) return;
|
||||
if (this.user.stats.lvl === 0) return;
|
||||
@@ -252,10 +282,6 @@ export default {
|
||||
const mana = after - before;
|
||||
this.mp(mana);
|
||||
},
|
||||
userLvl (after, before) {
|
||||
if (after <= before || this.$store.state.isRunningYesterdailies) return;
|
||||
this.showLevelUpNotifications(after);
|
||||
},
|
||||
userClassSelect (after) {
|
||||
if (this.user.needsCron) return;
|
||||
if (!after) return;
|
||||
@@ -279,13 +305,16 @@ export default {
|
||||
if (after !== true) return;
|
||||
this.$root.$emit('bv::show::modal', 'quest-invitation');
|
||||
},
|
||||
userExpAndLvl (after, before) {
|
||||
this.displayUserExpAndLvlNotifications(after[0], before[0], after[1], before[1]);
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
Promise.all([
|
||||
this.$store.dispatch('user:fetch'),
|
||||
this.$store.dispatch('tasks:fetchUserTasks'),
|
||||
]).then(() => {
|
||||
this.checkUserAchievements();
|
||||
this.debounceCheckUserAchievements();
|
||||
|
||||
// @TODO: This is a timeout to ensure dom is loaded
|
||||
window.setTimeout(() => {
|
||||
@@ -310,6 +339,74 @@ export default {
|
||||
document.removeEventListener('keydown', this.checkNextCron);
|
||||
},
|
||||
methods: {
|
||||
showDeathModal () {
|
||||
this.playSound('Death');
|
||||
this.$root.$emit('bv::show::modal', 'death');
|
||||
},
|
||||
showNotificationWithModal (type, forceToModal) {
|
||||
const config = NOTIFICATIONS[type];
|
||||
|
||||
if (!config) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (config.achievement) {
|
||||
this.playSound('Achievement_Unlocked');
|
||||
} else if (config.sound) {
|
||||
this.playSound(config.sound);
|
||||
}
|
||||
|
||||
if (type === 'REBIRTH_ACHIEVEMENT') {
|
||||
// reload if the user hasn't clicked on the notification
|
||||
const timeOut = setTimeout(() => {
|
||||
window.location.reload(true);
|
||||
}, 60000);
|
||||
|
||||
this.text(config.label(this.$t), () => {
|
||||
// prevent the current reload timeout
|
||||
clearTimeout(timeOut);
|
||||
this.$root.$emit('bv::show::modal', config.modalId);
|
||||
}, false);
|
||||
} else if (forceToModal) {
|
||||
this.$root.$emit('bv::show::modal', config.modalId);
|
||||
} else {
|
||||
this.text(config.label(this.$t), () => {
|
||||
this.$root.$emit('bv::show::modal', config.modalId);
|
||||
}, false);
|
||||
}
|
||||
},
|
||||
debounceCheckUserAchievements: debounce(function debounceCheck () {
|
||||
this.checkUserAchievements();
|
||||
}, 700),
|
||||
displayUserExpAndLvlNotifications (afterExp, beforeExp, afterLvl, beforeLvl) {
|
||||
if (afterExp === beforeExp && afterLvl === beforeLvl) return;
|
||||
|
||||
// XP evaluation
|
||||
if (afterExp !== beforeExp) {
|
||||
if (this.user.stats.lvl === 0) return;
|
||||
|
||||
const lvlUps = afterLvl - beforeLvl;
|
||||
let exp = afterExp - beforeExp;
|
||||
|
||||
if (lvlUps > 0) {
|
||||
let level = Math.trunc(beforeLvl);
|
||||
exp += toNextLevel(level);
|
||||
|
||||
// loop if more than 1 lvl up
|
||||
for (let i = 1; i < lvlUps; i += 1) {
|
||||
level += 1;
|
||||
exp += toNextLevel(level);
|
||||
}
|
||||
}
|
||||
this.exp(exp);
|
||||
}
|
||||
|
||||
// Lvl evaluation
|
||||
if (afterLvl !== beforeLvl) {
|
||||
if (afterLvl <= beforeLvl || this.$store.state.isRunningYesterdailies) return;
|
||||
this.showLevelUpNotifications(afterLvl);
|
||||
}
|
||||
},
|
||||
checkUserAchievements () {
|
||||
if (this.user.needsCron) return;
|
||||
|
||||
@@ -320,8 +417,7 @@ export default {
|
||||
}
|
||||
|
||||
if (this.user.stats.hp <= 0) {
|
||||
this.playSound('Death');
|
||||
this.$root.$emit('bv::show::modal', 'death');
|
||||
this.showDeathModal();
|
||||
}
|
||||
|
||||
if (this.questCompleted) {
|
||||
@@ -468,37 +564,20 @@ export default {
|
||||
this.$root.$emit('bv::show::modal', 'won-challenge');
|
||||
break;
|
||||
case 'STREAK_ACHIEVEMENT':
|
||||
this.text(`${this.$t('streaks')}: ${this.user.achievements.streak}`);
|
||||
this.text(`${this.$t('streaks')}: ${this.user.achievements.streak}`, () => {
|
||||
if (!this.user.preferences.suppressModals.streak) {
|
||||
this.$root.$emit('bv::show::modal', 'streak');
|
||||
}
|
||||
});
|
||||
this.playSound('Achievement_Unlocked');
|
||||
if (!this.user.preferences.suppressModals.streak) {
|
||||
this.$root.$emit('bv::show::modal', 'streak');
|
||||
}
|
||||
break;
|
||||
case 'ULTIMATE_GEAR_ACHIEVEMENT':
|
||||
this.playSound('Achievement_Unlocked');
|
||||
this.$root.$emit('bv::show::modal', 'ultimate-gear');
|
||||
break;
|
||||
case 'REBIRTH_ACHIEVEMENT':
|
||||
this.playSound('Achievement_Unlocked');
|
||||
this.$root.$emit('bv::show::modal', 'rebirth');
|
||||
break;
|
||||
case 'GUILD_JOINED_ACHIEVEMENT':
|
||||
this.playSound('Achievement_Unlocked');
|
||||
this.$root.$emit('bv::show::modal', 'joined-guild');
|
||||
break;
|
||||
case 'CHALLENGE_JOINED_ACHIEVEMENT':
|
||||
this.playSound('Achievement_Unlocked');
|
||||
this.text(`${this.$t('achievement')}: ${this.$t('joinedChallenge')}`, () => {
|
||||
this.$root.$emit('bv::show::modal', 'joined-challenge');
|
||||
}, false);
|
||||
break;
|
||||
case 'INVITED_FRIEND_ACHIEVEMENT':
|
||||
this.playSound('Achievement_Unlocked');
|
||||
this.$root.$emit('bv::show::modal', 'invited-friend');
|
||||
break;
|
||||
case 'NEW_CONTRIBUTOR_LEVEL':
|
||||
this.playSound('Achievement_Unlocked');
|
||||
this.$root.$emit('bv::show::modal', 'contributor');
|
||||
this.showNotificationWithModal(notification.type);
|
||||
break;
|
||||
case 'CRON':
|
||||
if (notification.data) {
|
||||
@@ -571,7 +650,7 @@ export default {
|
||||
});
|
||||
}
|
||||
|
||||
this.checkUserAchievements();
|
||||
this.debounceCheckUserAchievements();
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -41,7 +41,11 @@ b-modal#send-gems(:title="title", :hide-footer="true", size='lg', @hide='onHide(
|
||||
//include ../formatting-help
|
||||
|
||||
.modal-footer
|
||||
button.btn.btn-primary(v-if='fromBal', @click='sendGift()') {{ $t("send") }}
|
||||
button.btn.btn-primary(
|
||||
v-if="fromBal",
|
||||
@click="sendGift()",
|
||||
: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
|
||||
@@ -103,6 +107,7 @@ export default {
|
||||
assistanceEmailObject: {
|
||||
hrefTechAssistanceEmail: `<a href="mailto:${TECH_ASSISTANCE_EMAIL}">${TECH_ASSISTANCE_EMAIL}</a>`,
|
||||
},
|
||||
sendingInProgress: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -130,6 +135,7 @@ export default {
|
||||
methods: {
|
||||
// @TODO move to payments mixin or action (problem is that we need notifications)
|
||||
async sendGift () {
|
||||
this.sendingInProgress = true;
|
||||
await this.$store.dispatch('members:transferGems', {
|
||||
message: this.gift.message,
|
||||
toUserId: this.userReceivingGems._id,
|
||||
@@ -139,7 +145,11 @@ export default {
|
||||
this.close();
|
||||
},
|
||||
onHide () {
|
||||
// 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 = '';
|
||||
this.sendingInProgress = false;
|
||||
},
|
||||
close () {
|
||||
this.$root.$emit('bv::hide::modal', 'send-gems');
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
td
|
||||
input(type='checkbox', v-model='user.preferences.emailNotifications[notification]',
|
||||
@change='set("emailNotifications", notification)')
|
||||
td
|
||||
td(v-if="onlyEmailsIds.indexOf(notification) === -1")
|
||||
input(type='checkbox', v-model='user.preferences.pushNotifications[notification]',
|
||||
@change='set("pushNotifications", notification)')
|
||||
hr
|
||||
@@ -46,7 +46,7 @@ export default {
|
||||
mixins: [notificationsMixin],
|
||||
data () {
|
||||
return {
|
||||
notificationsIds: [
|
||||
notificationsIds: Object.freeze([
|
||||
'newPM',
|
||||
'wonChallenge',
|
||||
'giftedGems',
|
||||
@@ -59,7 +59,13 @@ export default {
|
||||
'importantAnnouncements',
|
||||
'weeklyRecaps',
|
||||
'onboarding',
|
||||
],
|
||||
]),
|
||||
// list of email-only notifications
|
||||
onlyEmailsIds: Object.freeze([
|
||||
'importantAnnouncements',
|
||||
'weeklyRecaps',
|
||||
'onboarding',
|
||||
]),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
||||
@@ -62,7 +62,7 @@ layout-section(:title="$t('equipment')")
|
||||
import svgHealer from 'assets/svg/healer.svg';
|
||||
|
||||
import _filter from 'lodash/filter';
|
||||
import _sortBy from 'lodash/sortBy';
|
||||
import _orderBy from 'lodash/orderBy';
|
||||
import pinUtils from '../../../mixins/pinUtils';
|
||||
|
||||
const sortGearTypes = ['sortByType', 'sortByPrice', 'sortByCon', 'sortByPer', 'sortByStr', 'sortByInt'].map(g => ({id: g}));
|
||||
@@ -71,6 +71,7 @@ layout-section(:title="$t('equipment')")
|
||||
sortByType: 'type',
|
||||
sortByPrice: 'value',
|
||||
sortByCon: 'con',
|
||||
sortByPer: 'per',
|
||||
sortByStr: 'str',
|
||||
sortByInt: 'int',
|
||||
};
|
||||
@@ -116,9 +117,33 @@ layout-section(:title="$t('equipment')")
|
||||
return this.marketGearCategories.filter(c => c.id === this.selectedGroupGearByClass)[0];
|
||||
},
|
||||
sortedGearItems () {
|
||||
let category = _filter(this.marketGearCategories, ['identifier', this.selectedGroupGearByClass]);
|
||||
let result = this.filterGearItems();
|
||||
let selectedSortKey = sortGearTypeMap[this.selectedSortGearBy.id];
|
||||
let sortingByStat = selectedSortKey !== 'type' && selectedSortKey !== 'value';
|
||||
let order = sortingByStat ? 'desc' : 'asc';
|
||||
|
||||
let result = _filter(category[0].items, (gear) => {
|
||||
// split into unlocked and locked, then apply selected sort
|
||||
return _orderBy(result, ['locked', selectedSortKey], ['asc', order]);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getClassName (classType) {
|
||||
if (classType === 'wizard') {
|
||||
return this.$t('mage');
|
||||
} else {
|
||||
return this.$t(classType);
|
||||
}
|
||||
},
|
||||
gearSelected (item) {
|
||||
if (!item.locked) {
|
||||
this.$root.$emit('buyModal::showItem', item);
|
||||
}
|
||||
},
|
||||
filterGearItems () {
|
||||
let category = _filter(this.marketGearCategories, ['identifier', this.selectedGroupGearByClass]);
|
||||
let items = category[0].items;
|
||||
|
||||
return _filter(items, (gear) => {
|
||||
if (this.hideLocked && gear.locked) {
|
||||
return false;
|
||||
}
|
||||
@@ -136,26 +161,6 @@ layout-section(:title="$t('equipment')")
|
||||
// hide already owned
|
||||
return !this.userItems.gear.owned[gear.key];
|
||||
});
|
||||
|
||||
// first all unlocked
|
||||
// then the selected sort
|
||||
result = _sortBy(result, [(item) => item.locked, sortGearTypeMap[this.selectedSortGearBy.id]]);
|
||||
|
||||
return result;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getClassName (classType) {
|
||||
if (classType === 'wizard') {
|
||||
return this.$t('mage');
|
||||
} else {
|
||||
return this.$t(classType);
|
||||
}
|
||||
},
|
||||
gearSelected (item) {
|
||||
if (!item.locked) {
|
||||
this.$root.$emit('buyModal::showItem', item);
|
||||
}
|
||||
},
|
||||
},
|
||||
created () {
|
||||
|
||||
@@ -33,7 +33,7 @@ transition(name="fade")
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.notification {
|
||||
border-radius: 1000px;
|
||||
border-radius: 30px;
|
||||
background-color: #24cc8f;
|
||||
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.16), 0 1px 4px 0 rgba(26, 24, 29, 0.12);
|
||||
color: white;
|
||||
@@ -43,7 +43,6 @@ transition(name="fade")
|
||||
}
|
||||
|
||||
.info {
|
||||
max-height: 56px;
|
||||
background-color: #46a7d9;
|
||||
padding-top: .5em;
|
||||
}
|
||||
@@ -146,20 +145,19 @@ export default {
|
||||
beforeDestroy () {
|
||||
clearTimeout(this.timer);
|
||||
},
|
||||
watch: {
|
||||
show () {
|
||||
this.$store.dispatch('snackbars:remove', this.notification);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleOnClick () {
|
||||
if (typeof this.notification.onClick === 'function') {
|
||||
this.notification.onClick();
|
||||
}
|
||||
|
||||
this.show = false;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
show () {
|
||||
this.$store.dispatch('snackbars:remove', this.notification);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
message () {
|
||||
if (this.notification.flavorMessage) {
|
||||
|
||||
@@ -42,6 +42,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
.home-header, .home-header .btn {
|
||||
font-family: 'Varela Round', sans-serif;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.btn-primary.pull-right {
|
||||
height: 2.5em;
|
||||
margin: auto 0px auto auto;
|
||||
@@ -66,9 +71,8 @@
|
||||
|
||||
.nav-item {
|
||||
.nav-link {
|
||||
font-size: 16px;
|
||||
font-size: 16px !important;
|
||||
color: $white;
|
||||
font-weight: bold;
|
||||
line-height: 1.5;
|
||||
padding: 16px 24px;
|
||||
transition: none;
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
span {{$t('or')}}
|
||||
.form(@keyup.enter="register()")
|
||||
p.form-text {{$t('usernameLimitations')}}
|
||||
input#usernameInput.form-control(type='text', placeholder='Login Name', v-model='username', :class='{"input-valid": usernameValid, "input-invalid": usernameInvalid}')
|
||||
input#usernameInput.form-control(type='text', :placeholder='$t("username")', v-model='username', :class='{"input-valid": usernameValid, "input-invalid": usernameInvalid}')
|
||||
.input-error(v-for="issue in usernameIssues") {{ issue }}
|
||||
input.form-control(type='email', placeholder='Email', v-model='email', :class='{"input-invalid": emailInvalid, "input-valid": emailValid}')
|
||||
input.form-control(type='password', placeholder='Password', v-model='password', :class='{"input-valid": password.length > 3}')
|
||||
input.form-control(type='password', placeholder='Confirm Password', v-model='passwordConfirm', :class='{"input-invalid": passwordConfirmInvalid, "input-valid": passwordConfirmValid}')
|
||||
input.form-control(type='email', :placeholder='$t("email")', v-model='email', :class='{"input-invalid": emailInvalid, "input-valid": emailValid}')
|
||||
input.form-control(type='password', :placeholder='$t("password")', v-model='password', :class='{"input-valid": password.length > 3}')
|
||||
input.form-control(type='password', :placeholder='$t("confirmPassword")', v-model='passwordConfirm', :class='{"input-invalid": passwordConfirmInvalid, "input-valid": passwordConfirmValid}')
|
||||
p.form-text(v-once, v-html="$t('termsAndAgreement')")
|
||||
button.sign-up(@click="register()") {{$t('signup')}}
|
||||
.col-12
|
||||
@@ -126,6 +126,8 @@
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
@import url('https://fonts.googleapis.com/css?family=Varela+Round');
|
||||
|
||||
#front {
|
||||
.form-text a {
|
||||
color: #fff !important;
|
||||
@@ -194,6 +196,11 @@
|
||||
.pixel-horizontal-3 {
|
||||
color: #271b3d;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6, button, .strike > span, input {
|
||||
font-family: 'Varela Round', sans-serif;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
#intro-signup {
|
||||
@@ -256,6 +263,7 @@
|
||||
.strike > span {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
line-height: 1.14;
|
||||
}
|
||||
|
||||
.strike > span:before,
|
||||
@@ -362,13 +370,17 @@
|
||||
}
|
||||
|
||||
strong {
|
||||
font-size: 20px;
|
||||
font-size: 24px;
|
||||
font-family: 'Varela Round', sans-serif;
|
||||
line-height: 1.33;
|
||||
}
|
||||
}
|
||||
|
||||
#use-cases {
|
||||
strong {
|
||||
font-size: 20px;
|
||||
font-size: 24px;
|
||||
font-family: 'Varela Round', sans-serif;
|
||||
line-height: 1.33;
|
||||
}
|
||||
|
||||
img {
|
||||
@@ -445,6 +457,11 @@
|
||||
|
||||
.featured {
|
||||
text-align: center;
|
||||
font-family: 'Varela Round', sans-serif;
|
||||
|
||||
strong {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
vertical-align: bottom;
|
||||
|
||||
@@ -113,7 +113,7 @@
|
||||
.task {
|
||||
margin-bottom: 2px;
|
||||
box-shadow: 0 2px 2px 0 rgba($black, 0.16), 0 1px 4px 0 rgba($black, 0.12);
|
||||
background: transparent;
|
||||
background: white;
|
||||
border-radius: 2px;
|
||||
position: relative;
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
span.hint(:popover-title='$t(statInfo.title)', popover-placement='right',
|
||||
:popover='$t(statInfo.popover)', popover-trigger='mouseenter')
|
||||
.stat-title(:class='stat') {{ $t(statInfo.title) }}
|
||||
strong.number {{ statsComputed[stat] | floorWholeNumber }}
|
||||
strong.number {{totalStatPoints(stat) | floorWholeNumber}}
|
||||
.col-12.col-md-6
|
||||
ul.bonus-stats
|
||||
li
|
||||
@@ -113,7 +113,7 @@
|
||||
| {{statsComputed.classBonus[stat]}}
|
||||
li
|
||||
strong {{$t('allocated')}}:
|
||||
| {{user.stats[stat]}}
|
||||
| {{totalAllocatedStats(stat)}}
|
||||
li
|
||||
strong {{$t('buffs')}}:
|
||||
| {{user.stats.buffs[stat]}}
|
||||
@@ -124,7 +124,7 @@
|
||||
h3
|
||||
| {{$t('statPoints')}}
|
||||
.counter.badge(v-if='user.stats.points || userLevel100Plus')
|
||||
| {{user.stats.points}}
|
||||
| {{pointsRemaining}}
|
||||
.col-12.col-md-6
|
||||
.float-right
|
||||
toggle-switch(
|
||||
@@ -137,7 +137,7 @@
|
||||
.box.white.row.col-12
|
||||
.col-9
|
||||
div(:class='stat') {{ $t(stats[stat].title) }}
|
||||
.number {{ user.stats[stat] }}
|
||||
.number {{totalAllocatedStats(stat)}}
|
||||
.points {{$t('pts')}}
|
||||
.col-3
|
||||
div
|
||||
@@ -157,7 +157,7 @@
|
||||
import Content from '../../../common/script/content';
|
||||
import { beastMasterProgress, mountMasterProgress } from '../../../common/script/count';
|
||||
import autoAllocate from '../../../common/script/fns/autoAllocate';
|
||||
import allocate from '../../../common/script/ops/stats/allocate';
|
||||
import allocateBulk from '../../../common/script/ops/stats/allocateBulk';
|
||||
import statsComputed from '../../../common/script/libs/statsComputed';
|
||||
|
||||
import axios from 'axios';
|
||||
@@ -239,14 +239,27 @@
|
||||
return this.user.stats.lvl >= 100;
|
||||
},
|
||||
showStatsSave () {
|
||||
const statsAreBeingUpdated = Object.values(this.statUpdates).find(stat => stat > 0);
|
||||
return Boolean(this.user.stats.points) || statsAreBeingUpdated;
|
||||
return Boolean(this.user.stats.points);
|
||||
},
|
||||
pointsRemaining () {
|
||||
let points = this.user.stats.points;
|
||||
Object.values(this.statUpdates).forEach(value => {
|
||||
points -= value;
|
||||
});
|
||||
return points;
|
||||
},
|
||||
|
||||
},
|
||||
methods: {
|
||||
getGearTitle (key) {
|
||||
return this.flatGear[key].text();
|
||||
},
|
||||
totalAllocatedStats (stat) {
|
||||
return this.user.stats[stat] + this.statUpdates[stat];
|
||||
},
|
||||
totalStatPoints (stat) {
|
||||
return this.statsComputed[stat] + this.statUpdates[stat];
|
||||
},
|
||||
totalCount (objectToCount) {
|
||||
let total = size(objectToCount);
|
||||
return total;
|
||||
@@ -292,14 +305,12 @@
|
||||
return display;
|
||||
},
|
||||
allocate (stat) {
|
||||
allocate(this.user, {query: { stat }});
|
||||
this.statUpdates[stat] += 1;
|
||||
if (this.pointsRemaining === 0) return;
|
||||
this.statUpdates[stat]++;
|
||||
},
|
||||
deallocate (stat) {
|
||||
if (this.user.stats[stat] === 0) return;
|
||||
this.user.stats[stat] -= 1;
|
||||
this.user.stats.points += 1;
|
||||
this.statUpdates[stat] -= 1;
|
||||
if (this.statUpdates[stat] === 0) return;
|
||||
this.statUpdates[stat]--;
|
||||
},
|
||||
async saveAttributes () {
|
||||
this.loading = true;
|
||||
@@ -309,10 +320,7 @@
|
||||
if (this.statUpdates[stat] > 0) statUpdates[stat] = this.statUpdates[stat];
|
||||
});
|
||||
|
||||
await axios.post('/api/v4/user/allocate-bulk', {
|
||||
stats: statUpdates,
|
||||
});
|
||||
|
||||
// reset statUpdates to zero before request to avoid display errors while waiting for server
|
||||
this.statUpdates = {
|
||||
str: 0,
|
||||
int: 0,
|
||||
@@ -320,6 +328,12 @@
|
||||
per: 0,
|
||||
};
|
||||
|
||||
allocateBulk(this.user, { body: { stats: statUpdates } });
|
||||
|
||||
await axios.post('/api/v4/user/allocate-bulk', {
|
||||
stats: statUpdates,
|
||||
});
|
||||
|
||||
this.loading = false;
|
||||
},
|
||||
allocateNow () {
|
||||
|
||||
@@ -47,6 +47,5 @@ export function round (number, nDigits) {
|
||||
}
|
||||
|
||||
export function getXPMessage (val) {
|
||||
if (val < -50) return; // don't show when they level up (resetting their exp)
|
||||
return `${getSign(val)} ${round(val)}`;
|
||||
}
|
||||
@@ -1,44 +1,44 @@
|
||||
export default [
|
||||
{
|
||||
name: 'beffymaroo',
|
||||
type: 'Staff',
|
||||
uuid: '9fe7183a-4b79-4c15-9629-a1aee3873390',
|
||||
},
|
||||
// {
|
||||
// name: 'lefnire',
|
||||
// type: 'Staff',
|
||||
// uuid: '00000000-0000-4000-9000-000000000000',
|
||||
// },
|
||||
{
|
||||
name: 'Lemoness',
|
||||
type: 'Staff',
|
||||
uuid: '7bde7864-ebc5-4ee2-a4b7-1070d464cdb0',
|
||||
},
|
||||
{
|
||||
name: 'paglias',
|
||||
type: 'Staff',
|
||||
uuid: 'ed4c688c-6652-4a92-9d03-a5a79844174a',
|
||||
},
|
||||
{
|
||||
name: 'redphoenix',
|
||||
type: 'Staff',
|
||||
uuid: 'cb46ad54-8c78-4dbc-a8ed-4e3185b2b3ff',
|
||||
},
|
||||
{
|
||||
name: 'paglias',
|
||||
type: 'Staff',
|
||||
uuid: 'ed4c688c-6652-4a92-9d03-a5a79844174a',
|
||||
},
|
||||
{
|
||||
name: 'SabreCat',
|
||||
type: 'Staff',
|
||||
uuid: '7f14ed62-5408-4e1b-be83-ada62d504931',
|
||||
},
|
||||
{
|
||||
name: 'TheHollidayInn',
|
||||
type: 'Staff',
|
||||
uuid: '206039c6-24e4-4b9f-8a31-61cbb9aa3f66',
|
||||
},
|
||||
{
|
||||
name: 'viirus',
|
||||
type: 'Staff',
|
||||
uuid: 'a327d7e0-1c2e-41be-9193-7b30b484413f',
|
||||
},
|
||||
{
|
||||
name: 'beffymaroo',
|
||||
type: 'Staff',
|
||||
uuid: '9fe7183a-4b79-4c15-9629-a1aee3873390',
|
||||
},
|
||||
{
|
||||
name: 'Apollo',
|
||||
type: 'Staff',
|
||||
uuid: '9b2f4123-f749-4f74-85e2-ce31ce778435',
|
||||
},
|
||||
{
|
||||
name: 'Piyo',
|
||||
type: 'Staff',
|
||||
uuid: '61b2c855-0a30-444c-bcc6-1cac876460b0',
|
||||
},
|
||||
{
|
||||
name: 'It\'s Bailey',
|
||||
type: 'Moderator',
|
||||
@@ -64,11 +64,6 @@ export default [
|
||||
type: 'Moderator',
|
||||
uuid: '28771972-ca6d-4c03-8261-e1734aa7d21d',
|
||||
},
|
||||
// {
|
||||
// name: 'Daniel the Bard',
|
||||
// type: 'Moderator',
|
||||
// uuid: '1f7c4a74-03a3-4b2c-b015-112d0acbd593',
|
||||
// },
|
||||
{
|
||||
name: 'deilann 5.0.5b',
|
||||
type: 'Moderator',
|
||||
|
||||
@@ -29,9 +29,7 @@ export default {
|
||||
},
|
||||
exp (val) {
|
||||
const message = getXPMessage(val);
|
||||
if (message) {
|
||||
this.notify(message, 'xp', 'glyphicon glyphicon-star', this.sign(val));
|
||||
}
|
||||
this.notify(message, 'xp', 'glyphicon glyphicon-star', this.sign(val));
|
||||
},
|
||||
error (error) {
|
||||
this.notify(error, 'error', 'glyphicon glyphicon-exclamation-sign');
|
||||
@@ -60,8 +58,8 @@ export default {
|
||||
itemName,
|
||||
}));
|
||||
},
|
||||
streak (val) {
|
||||
this.notify(`${val}`, 'streak');
|
||||
streak (val, onClick) {
|
||||
this.notify(`${val}`, 'streak', null, null, onClick, typeof onClick === 'undefined');
|
||||
},
|
||||
text (val, onClick, timeout) {
|
||||
if (!val) return;
|
||||
|
||||
@@ -46,8 +46,6 @@ export async function postChat (store, payload) {
|
||||
message: payload.message,
|
||||
});
|
||||
|
||||
// @TODO: pusherSocketId: $rootScope.pusherSocketId, // to make sure the send doesn't get notified of it's own message
|
||||
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
|
||||
@@ -139,8 +139,6 @@ export function newStuffLater (store) {
|
||||
export async function rebirth () {
|
||||
let result = await axios.post('/api/v4/user/rebirth');
|
||||
|
||||
window.location.reload(true);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -99,6 +99,7 @@
|
||||
"noChallengeTitle": "Нямате никакви предизвикателства.",
|
||||
"challengeDescription1": "Предизвикателствата са обществени събития, в които играчите се състезават и печелят награди като изпълняват няколко свързани по някакъв начин задачи.",
|
||||
"challengeDescription2": "Открийте препоръчани за Вас предизвикателства според интересите Ви, разгледайте обществените предизвикателства на Хабитика, или създайте свои собствени предизвикателства.",
|
||||
"noChallengeMatchFilters": "Не можем да открием съответстващи предизвикателства.",
|
||||
"createdBy": "Създадено от",
|
||||
"joinChallenge": "Присъединяване към предизвикателството",
|
||||
"leaveChallenge": "Напускане на предизвикателството",
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
"autoEquipPopoverText": "Изберете това, за да екипирате всеки предмет в момента, когато го купите.",
|
||||
"costumeDisabled": "Вие изключихте костюма си.",
|
||||
"gearAchievement": "Вие спечелихте постижението „Последното снаряжение“ заради това, че достигнахте максималното снаряжение за класа си! Получавате следните пълни комплекти:",
|
||||
"gearAchievementNotification": "Вие спечелихте постижението „Последното снаряжение“ заради това, че достигнахте максималното снаряжение за класа си!",
|
||||
"moreGearAchievements": "За да получите още значки „Последното снаряжение“, променете класа си в <a href='/user/settings/site' target='_blank'>страницата „Настройки > Уеб сайт</a> и купете екипировката на новия си клас!",
|
||||
"armoireUnlocked": "За още екипировка, прегледайте <strong>Омагьосания гардероб!</strong> Щракнете наградата на Омагьосания гардероб и ще имате шанс да получите специална екипировка! Той може да Ви даде също опит или храна.",
|
||||
"ultimGearName": "Последното снаряжение — <%= ultClass %>",
|
||||
|
||||
@@ -176,6 +176,9 @@
|
||||
"questEggKangarooText": "Кенгуру",
|
||||
"questEggKangarooMountText": "Кенгуру",
|
||||
"questEggKangarooAdjective": "енергично",
|
||||
"questEggAlligatorText": "Алигатор",
|
||||
"questEggAlligatorMountText": "Алигатор",
|
||||
"questEggAlligatorAdjective": "хитър",
|
||||
"eggNotes": "Намерете излюпваща отвара, която да излеете върху това яйце и от него ще се излюпи <%= eggAdjective(locale) %> <%= eggText(locale) %>.",
|
||||
"hatchingPotionBase": "Нормален цвят",
|
||||
"hatchingPotionWhite": "Бял цвят",
|
||||
|
||||
@@ -684,6 +684,8 @@
|
||||
"armorMystery201808Notes": "Тази броня е направена от отчупени люспи на неуловимия (и изключително горещ) дракон от лава. Не променя показателите. Предмет за абонати: август 2018 г.",
|
||||
"armorMystery201809Text": "Броня от есенни листа",
|
||||
"armorMystery201809Notes": "Вие не сте просто малко и страховито листенце, а носите най-красивите цветове за сезона! Не променя показателите. Предмет за абонати: септември 2018 г.",
|
||||
"armorMystery201810Text": "Тъмногорски одежди",
|
||||
"armorMystery201810Notes": "Изключителната топлина, която дават тези одежди, ще Ви защити от студа в призрачните места. Не променя показателите. Предмет за абонати: октомври 2018 г.",
|
||||
"armorMystery301404Text": "Изтънчен костюм",
|
||||
"armorMystery301404Notes": "Спретнат и елегантен! Не променя показателите. Предмет за абонати: февруари 3015 г.",
|
||||
"armorMystery301703Text": "Изтънчена паунова рокля",
|
||||
@@ -1110,6 +1112,8 @@
|
||||
"headMystery201808Notes": "Светещите рога на тази качулка ще Ви осветят пътя през подземните пещери. Не променя показателите. Предмет за абонати: август 2018 г.",
|
||||
"headMystery201809Text": "Корона от есенни цветя",
|
||||
"headMystery201809Notes": "Последните цветя на топлите есенни дни напомнят за красотата на този сезон. Не променя показателите. Предмет за абонати: септември 2018 г.",
|
||||
"headMystery201810Text": "Тъмногорски шлем",
|
||||
"headMystery201810Notes": "Ако се окаже, че пътят Ви минава през някое зловещо място, то червените очи на този шлем със сигурност ще изплашат враговете, които могат да се появят на пътя Ви. Не променя показателите. Предмет за абонати: октомври 2018 г.",
|
||||
"headMystery301404Text": "Украсен цилиндър",
|
||||
"headMystery301404Notes": "Украсен цилиндър за най-изтънчените и високопоставени членове на обществото. Не променя показателите. Предмет за абонати: януари 3015 г.",
|
||||
"headMystery301405Text": "Обикновен цилиндър",
|
||||
|
||||
@@ -340,15 +340,12 @@
|
||||
"canceledGroupPlan": "Груповият план е прекратен",
|
||||
"groupPlanCanceled": "Груповият план ще стане неактивен на",
|
||||
"purchasedGroupPlanPlanExtraMonths": "Имате оставащи средства за <%= months %> месеца от груповия план.",
|
||||
"addManagers": "Добавяне на управители",
|
||||
"addManager": "Добавяне на управител",
|
||||
"removeManager": "Премахване",
|
||||
"addManager": "Назначаване на управител",
|
||||
"removeManager2": "Премахване на ролята на управител",
|
||||
"userMustBeMember": "Потребителят трябва да бъде член",
|
||||
"userIsNotManager": "Потребителят не е управител",
|
||||
"canOnlyApproveTaskOnce": "Тази задача е вече одобрена.",
|
||||
"addTaskToGroupPlan": "Създаване",
|
||||
"leaderMarker": "— Водач",
|
||||
"managerMarker": "— Управител",
|
||||
"joinedGuild": "Присъединил(а) се към гилдия",
|
||||
"joinedGuildText": "Потопил(а) се в обществената част на Хабитика чрез присъединяване към гилдия!",
|
||||
"badAmountOfGemsToPurchase": "Стойността трябва да бъде поне 1.",
|
||||
@@ -395,12 +392,12 @@
|
||||
"noGuildsTitle": "Не членувате в нито една гилдия.",
|
||||
"noGuildsParagraph1": "Гилдиите са обществени групи създадени от другите играчи, които могат да Ви помогнат, да поддържат отговорността Ви, както и да бъдат място за насърчаващи разговори.",
|
||||
"noGuildsParagraph2": "Отворете раздела за разглеждане, за да открите препоръчани за Вас гилдии според интересите Ви, разгледайте обществените гилдии на Хабитика, или създайте своя собствена гилдия.",
|
||||
"noGuildsMatchFilters": "Не можем да открием съответстващи гилдии.",
|
||||
"privateDescription": "Частните гилдии не се показват в списъка с гилдии на Хабитика. Нови членове могат да бъдат добавени само чрез покана.",
|
||||
"removeInvite": "Премахване на поканата",
|
||||
"removeMember": "Премахване на члена",
|
||||
"sendMessage": "Изпращане на съобщение",
|
||||
"removeManager2": "Премахване на управителя",
|
||||
"promoteToLeader": "Повишаване във водач",
|
||||
"promoteToLeader": "Прехвърляне на притежанието",
|
||||
"inviteFriendsParty": "Ако поканите приятели в групата си, ще получите изключителния <br/> свитък с мисията да се биете заедно срещу Василисъка!",
|
||||
"upgradeParty": "Надграждане на групата",
|
||||
"createParty": "Създаване на група",
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"veteranTiger": "Тигър ветеран",
|
||||
"veteranLion": "Лъв ветеран",
|
||||
"veteranBear": "Мечка ветеран",
|
||||
"veteranFox": "Лисица ветеран",
|
||||
"cerberusPup": "Кученце цербер",
|
||||
"hydra": "Хидра",
|
||||
"mantisShrimp": "Скарида-богомолка",
|
||||
|
||||
@@ -618,5 +618,11 @@
|
||||
"questKangarooDropKangarooEgg": "Кенгуру (яйце)",
|
||||
"questKangarooUnlockText": "Отключва възможността за купуване на яйца на кенгуру от пазара.",
|
||||
"forestFriendsText": "Пакет мисии „Горски приятели“",
|
||||
"forestFriendsNotes": "Съдържа: „Пролетен дух“, „Ежко-Звережко“ и „Оплетеното дърво“. Наличен до 30 септември."
|
||||
"forestFriendsNotes": "Съдържа: „Пролетен дух“, „Ежко-Звережко“ и „Оплетеното дърво“. Наличен до 30 септември.",
|
||||
"questAlligatorText": "Ведна-гаторът",
|
||||
"questAlligatorNotes": "„Еха!“ – възкликва @gully. „Ведна-гатор в естествената си среда! Внимавай, той разсейва плячката си с неща, на които изглежда, че трябва да обърнеш внимание ВЕДНАГА, и се храни с неотметнатите ежедневни задачи, които неминуемо са резултат на това разсейване.“ – Ти замлъкваш, за да не привлечеш вниманието му, но безуспешно. Ведна-гаторът те забелязва и се втурва към теб! Разсейващи гласове започват да се чуват откъм Блатата на застоя, привличайки вниманието ти: „Прочети тази публикация! Виж тази снимка! Обърни ми внимание ВЕДНАГА!“ – ти се впускаш в контраатака, като се опитваш да завършиш ежедневните си задачи и да поддържаш добрите си навици, за да отблъснеш проклетия Ведна-гатор.",
|
||||
"questAlligatorCompletion": "След като успяваш да фокусираш вниманието си върху това, което е наистина важно, а не върху разсейванията на Ведна-гатора, той отстъпва. Победа! „Това яйца ли са? Приличат ми на яйца на алигатор“ – пита @mfonda. – „Ако се грижим правилно за тях, те ще се превърнат в лоялни любимци и надеждни превози“ – отговаря @UncommonCriminal, докато ти подава три, за които да се грижиш. Да се надяваме, че всичко ще бъде наред, иначе Ведна-гаторът може пак да се върне…",
|
||||
"questAlligatorBoss": "Ведна-гаторът",
|
||||
"questAlligatorDropAlligatorEgg": "Алигатор (яйце)",
|
||||
"questAlligatorUnlockText": "Отключва възможността за купуване на яйца на алигатор от пазара."
|
||||
}
|
||||
@@ -148,6 +148,7 @@
|
||||
"mysterySet201807": "Комплект на морския змей",
|
||||
"mysterySet201808": "Комплект на дракон от лава",
|
||||
"mysterySet201809": "Комплект на есенната броня",
|
||||
"mysterySet201810": "Тъмногорски комплект",
|
||||
"mysterySet301404": "Стандартен изтънчен комплект",
|
||||
"mysterySet301405": "Комплект изтънчени принадлежности",
|
||||
"mysterySet301703": "Изтънчен паунов комплект",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"achievement": "Úspěch",
|
||||
"share": "Sdílet",
|
||||
"onwards": "Kupředu!",
|
||||
"levelup": "Díky dosažení tvých cílů v reálném životě jsi se dostal na vyšší úroveň, a jsi díky tomu plně uzdraven!",
|
||||
"levelup": "Dosáhl jsi svých cílů v reálném životě, a proto jsi postoupil na vyšší úroveň a jsi plně uzdraven!",
|
||||
"reachedLevel": "Dosáhl jsi úrovně <%= level %>",
|
||||
"achievementLostMasterclasser": "Dokončení výprav: Série Mistra třídy",
|
||||
"achievementLostMasterclasserText": "Splnil všech šestnáct výprav v sérii výprav Mistra třídy a vyřešil záhadu Ztraceného Mistra!"
|
||||
|
||||
@@ -382,10 +382,10 @@
|
||||
"backgroundCozyBarnText": "Útulná stodola",
|
||||
"backgroundCozyBarnNotes": "Odpočiň si se svými mazlíčky ve stáji.",
|
||||
"backgrounds102018": "SET 53: Vydáno v říjnu 2018",
|
||||
"backgroundBayouText": "Bayou",
|
||||
"backgroundBayouNotes": "Bask in the fireflies' glow on the misty Bayou.",
|
||||
"backgroundCreepyCastleText": "Creepy Castle",
|
||||
"backgroundCreepyCastleNotes": "Dare to approach a Creepy Castle.",
|
||||
"backgroundDungeonText": "Dungeon",
|
||||
"backgroundDungeonNotes": "Rescue the prisoners of a spooky Dungeon."
|
||||
"backgroundBayouText": "Potok",
|
||||
"backgroundBayouNotes": "Kochej se září světlušek nad mlhou zastřeným potokem.",
|
||||
"backgroundCreepyCastleText": "Strašidelný hrad",
|
||||
"backgroundCreepyCastleNotes": "Odvaž se přiblížit k strašidelnému hradu.",
|
||||
"backgroundDungeonText": "Žalář",
|
||||
"backgroundDungeonNotes": "Vysvoboď vězně ze zlověstného žaláře."
|
||||
}
|
||||
@@ -99,6 +99,7 @@
|
||||
"noChallengeTitle": "Nemáš žádné výzvy",
|
||||
"challengeDescription1": "Výzvy jsou komunitní události, ve kterých hráči soutěží a získávají odměny za plnění několika příbuzných úkolů.",
|
||||
"challengeDescription2": "Vyhledej doporučené Výzvy podle tvých zálib, procházej veřejné výzvy a nebo vytvoř svoji vlastní.",
|
||||
"noChallengeMatchFilters": "Nenalezli jsme žádné odpovídající výzvy.",
|
||||
"createdBy": "Vytvořil",
|
||||
"joinChallenge": "Připojit se k výzvě",
|
||||
"leaveChallenge": "Opustit výzvu",
|
||||
|
||||
@@ -80,6 +80,7 @@
|
||||
"autoEquipPopoverText": "Zvol tuto možnost pro automatické nasazení koupeného vybavení.",
|
||||
"costumeDisabled": "Vypnul jsi svůj kostým",
|
||||
"gearAchievement": "Získal jsi Ocenění \"Maximální Vybavení\" za vylepšení výbavy na maximální set vybavení pro povolání! Získal jsi následující kompletní sety:",
|
||||
"gearAchievementNotification": "Získal jsi ocenění \"Ultimátní výbava\" za vylepšení vybavení daného povolání na maximální úroveň!",
|
||||
"moreGearAchievements": "Abys získal více ocenění Ultimátního Vybavení, změň své povolání v <a href='/user/settings/site' target='_blank'>Nastavení - Stránka</a>, a nakup si vybavení pro své nové povolání!",
|
||||
"armoireUnlocked": "Také jsi odemkl <strong>Začarovanou almaru!</strong> Klikni na Odměnu začarované almary a náhodně získej speciální Vybavení! Také ti může náhodně dát Zkušenostní body nebo jídlo.",
|
||||
"ultimGearName": "Ultimátní výbava - <%= ultClass %>",
|
||||
@@ -183,7 +184,7 @@
|
||||
"lostMana": "Utratil jsi několik many",
|
||||
"lostHealth": "Ztratil jsi několik zdraví",
|
||||
"lostExperience": "Ztratil jsi několik zkušeností",
|
||||
"displayNameDescription1": "This is what appears in messages you post in the Tavern, guilds, and party chat, along with what is displayed on your avatar. To change it, click the Edit button above. If instead you want to change your username, go to",
|
||||
"displayNameDescription1": "Toto se zobrazí ve zprávách, které uveřejníš v Krčmě, ceších, a chatu v družině, spolu s tvým avatarem. Jestli to chceš změnit, klikni na tlačítko Editovat. Jestli chceš ale změnit svoje přihlašovací jméno, jdi na",
|
||||
"displayNameDescription2": "Nastavení -> Stránka",
|
||||
"displayNameDescription3": "sekci Registrace, tam to najdeš.",
|
||||
"unequipBattleGear": "Odebrat válečnou zbroj",
|
||||
|
||||
@@ -169,13 +169,16 @@
|
||||
"questEggBadgerAdjective": "rušný",
|
||||
"questEggSquirrelText": "veverka",
|
||||
"questEggSquirrelMountText": "veverka",
|
||||
"questEggSquirrelAdjective": "a bushy-tailed",
|
||||
"questEggSquirrelAdjective": "čiperná",
|
||||
"questEggSeaSerpentText": "Mořský had",
|
||||
"questEggSeaSerpentMountText": "Mořský had",
|
||||
"questEggSeaSerpentAdjective": "Třpitivý",
|
||||
"questEggKangarooText": "Klokan",
|
||||
"questEggKangarooMountText": "Klokan",
|
||||
"questEggKangarooAdjective": "nadšený",
|
||||
"questEggAlligatorText": "Aligátor",
|
||||
"questEggAlligatorMountText": "Aligátor",
|
||||
"questEggAlligatorAdjective": "prohnaný",
|
||||
"eggNotes": "Najdi líhnoucí lektvar, nalij ho na vejce a to se vylíhne v <%= eggAdjective(locale) %> <%= eggText(locale) %>.",
|
||||
"hatchingPotionBase": "Základní",
|
||||
"hatchingPotionWhite": "Bílý",
|
||||
|
||||