Compare commits

..

94 Commits

Author SHA1 Message Date
Sabe Jones a5fc909f0d 4.67.1 2018-10-28 20:45:38 +00:00
Sabe Jones 30a5192e19 chore(i18n): update locales 2018-10-28 20:45:27 +00:00
Matteo Pagliazzi 79c0499672 Mongoose: use $type as the typeKey (#10789)
* use $type as the typeKey in mongoose

* fix and add tests
2018-10-28 15:42:48 -05:00
Sabe Jones 490531cc76 4.67.0 2018-10-25 21:36:13 +00:00
Sabe Jones 8cd4c502bc chore(i18n): update locales 2018-10-25 21:35:58 +00:00
Sabe Jones d8cacb653e chore(sprites): compile 2018-10-25 16:31:13 -05:00
Sabe Jones 59436a8bf7 feat(content): Mystery Items Oct 2018 2018-10-25 16:31:00 -05:00
Sabe Jones 6fade19f27 4.66.2 2018-10-25 20:32:06 +00:00
Sabe Jones 15d028a281 chore(i18n): update locales 2018-10-25 20:31:20 +00:00
Sabe Jones e028232527 Merge branch 'release' into develop 2018-10-24 18:35:55 +00:00
Sabe Jones e3b270a62e 4.66.1 2018-10-24 18:35:34 +00:00
Sabe Jones fceeacec3b chore(i18n): update locales 2018-10-24 18:35:27 +00:00
Matteo Pagliazzi f93c67e57c fix(amazon gift): do not reset the gift amount when opening the amazon modal 2018-10-24 20:29:27 +02:00
Sabe Jones 192dc26fbe Merge branch 'release' into develop 2018-10-23 22:50:49 +00:00
Sabe Jones 1c1f270f64 4.66.0 2018-10-23 22:50:25 +00:00
Sabe Jones 483768f4a7 chore(i18n): update locales 2018-10-23 22:49:30 +00:00
SabreCat 65031cef3a chore(sprites): compile 2018-10-23 22:45:47 +00:00
Sabe Jones 2fc1f46359 Veteran Pet ladder award for users affected by username changes (#10765)
* feat(usernames): Veteran Pet ladder award for affected users

* feat(content): Vet Pet Bailey etc.
2018-10-23 17:38:30 -05:00
Matteo Pagliazzi 30fd530576 fix(tests): more timeouts fixes 2018-10-23 20:23:52 +02:00
Matteo Pagliazzi f79999fde7 minor deps updates 2018-10-23 16:48:59 +02:00
Tressley Cahill 90d6e443ba Corrects the white bar above the header and updates the text styling (#10772) 2018-10-23 13:50:02 +02:00
Derek Kim 4ed1082558 fix for #10496: Newly subscribed accounts receive erroneous notification that they have Mystery Items (#10759)
* fix
Newly subscribed accounts receive erroneous notification that they have Mystery Items

* Added unit test for #10496

* Restored a previous unit test
2018-10-23 13:47:15 +02:00
Matteo Pagliazzi 00717eda76 fix(tests): increase timeout 2018-10-23 13:30:38 +02:00
Matteo Pagliazzi d1b86e6c14 Remove code for Pusher (#10774)
* remove pusher

* fix linting
2018-10-23 13:25:52 +02:00
Matteo Pagliazzi c813afba44 Upgrade mongoose (#10767)
* fix mongoose and upgrade

* fix more validations
2018-10-23 13:25:14 +02:00
Matteo Pagliazzi d49db6d367 upgrade csv-stringify (#10776) 2018-10-23 13:22:22 +02:00
Matteo Pagliazzi d6835aec56 upgrade method override (#10775) 2018-10-23 11:48:15 +02:00
Matteo Pagliazzi 960f7b5886 upgrade node-gcm (#10777) 2018-10-23 11:47:26 +02:00
Matteo Pagliazzi ff57e31f4f 4.65.7 2018-10-20 16:17:26 +02:00
Matteo Pagliazzi 6e21d154ae Do not throw an error when adding the same push device twice (#10770)
* do not throw an error when adding the same push device twice

* fix spelling

* fix linting
2018-10-20 14:52:02 +02:00
Tressley Cahill fe5beac91b Custom reward action background and font-color updates (#10769)
* fixes custom reward action background and font-color

* update to -10
2018-10-19 10:01:02 -05:00
Sabe Jones 52fd6a1451 4.65.6 2018-10-18 23:09:12 +00:00
Sabe Jones ae445555e9 fix(groups): don't show add manager for non-groups and non-leaders 2018-10-18 18:08:30 -05:00
Sabe Jones c4fc6671b4 4.65.5 2018-10-18 20:05:29 +00:00
Sabe Jones e7a096158e chore(i18n): update locales 2018-10-18 20:05:15 +00:00
Sabe Jones 98473fcfaa chore(news): Bailey 2018-10-18 15:00:21 -05:00
Sabe Jones e4300fc714 fix(registration): localize reg form placeholders 2018-10-18 14:48:46 -05:00
Matteo Pagliazzi ffba435923 fix #10756: do not show push notification settings for email only notifications 2018-10-18 14:21:35 +02:00
Matteo Pagliazzi 1f44444a50 Fix subcriptions remaining time disappearing after cancelling (#10761)
* add hasCancelled method for group/user, prevent cancelling a subscription twice

* wip

* paypal: do not cancel a subscription twice

* make sure hasCancelled and hasNotCancelled return a boolean result
2018-10-18 12:14:07 +02:00
Sabe Jones 061d990e39 Merge branch 'release' into develop 2018-10-15 20:20:55 +00:00
Sabe Jones 71f4e6bc08 4.65.4 2018-10-15 20:20:33 +00:00
Sabe Jones 659f160e22 chore(i18n): update locales 2018-10-15 20:20:25 +00:00
Trevor Ford 5f27bc5f90 Issue 10728: sort equipment by stat descending on Market page (#10734)
* sort equipment by stat descending in Market (issue #10728)

* fix sorting equipment by PER in Market (new issue?)

* move filter logic into method when sorting equipment in Market

* consolidate sorting in sortedGearItems() into one _orderBy call
2018-10-15 21:12:53 +02:00
negue 074837b274 check every armoire gear 'canOwn' method (#10760) 2018-10-15 20:11:28 +02:00
Matteo Pagliazzi aa517e0ad6 Merge branch 'negue/modal-notifications' into develop 2018-10-13 21:18:30 +02:00
Matteo Pagliazzi 5ca489dee7 Merge branch 'develop' into negue/modal-notifications 2018-10-13 21:18:16 +02:00
Rene Cordier fe39ef72ff Show accurate experience notifications (#10676)
* Show accurate experience notifications

Add unit tests for exp notifications

* use array to compute exp and lvl values for notification changes

* Add tests for user loosing xp cases
2018-10-13 20:24:23 +02:00
Carl Vuorinen eee5f2f1df No matching Guilds/Challenges message (#10744)
* Display message on My Guilds page when filters dont' match anything

* Display message on Discover Guilds page when filters dont' match anything

* Display message on My Challenges page when filters dont' match anything

* Display message on Discover Challenges page when filters dont' match anything

* Don't show Load More button when there is nothing to load

* Fix Guild search

Previously was not possible to clear after searching
2018-10-13 20:19:03 +02:00
Sabe Jones fd8572c28a Group Management Menu Fixes (#10704)
* fix(groups): more intelligent member actions

* fix(groups): further member action improvements

* fix(groups): don't show "Remove Manager" if user doesn't have authority

* fix(lint): bad if syntax

* fix(groups): unnecessary if on icon
2018-10-13 20:15:46 +02:00
Kirsty f161987e1e check officialPinnedItems for gala gear in market (#10745) 2018-10-13 20:07:30 +02:00
aszlig 2304d970a5 api: Fix a few API documentation typos (#10749)
Just fixes a few syntactic errors and typos.

Signed-off-by: aszlig <aszlig@nix.build>
2018-10-13 20:03:40 +02:00
Sabe Jones 25ed05ab0a Analytics: clean up old A/B test code & add username verify flag (#10754)
* chore(analytics): clean up old A/B test code & add username verify

* fix(lint): more AB cleanup
2018-10-13 13:03:20 -05:00
Sabe Jones 6f5b9ef119 fix(scripts): better error handling for script runner and GDPR 2018-10-12 15:27:31 +00:00
Sabe Jones c64ea0a9a9 4.65.3 2018-10-11 21:05:46 +00:00
Sabe Jones 2e36b896d4 chore(i18n): update locales 2018-10-11 21:04:30 +00:00
Sabe Jones 6fe73d431e Merge branch 'develop' into release 2018-10-11 16:01:56 -05:00
Sabe Jones 998621cefe feat(content): fall avatar customization 2018-10-11 16:01:32 -05:00
Matteo Pagliazzi 67bb179c25 gifts: prevent users from sending the same gift twice by clicking many times on the Send button 2018-10-11 19:01:15 +02:00
Sabe Jones c875861dab Merge branch 'release' into develop 2018-10-10 16:26:28 +00:00
Sabe Jones 418c18ddb2 4.65.2 2018-10-09 23:40:09 -05:00
Sabe Jones 0caab5c8d0 fix(news): missing footnote 2018-10-09 23:39:48 -05:00
Sabe Jones 218e65b04b Merge branch 'release' into develop 2018-10-09 21:33:49 -05:00
Sabe Jones fcd7ba77a7 4.65.1 2018-10-09 21:32:58 -05:00
Sabe Jones b0d177643c chore(sprites): compile 2018-10-09 21:32:38 -05:00
Sabe Jones c0e0b10a95 Merge branch 'release' into develop 2018-10-10 01:20:18 +00:00
Sabe Jones 0bee2caf2e 4.65.0 2018-10-10 01:19:52 +00:00
Sabe Jones e56d097b3a chore(i18n): update locales 2018-10-10 01:16:28 +00:00
Sabe Jones 8c63a9e31f feat(content): Alligator Pets and Spoopy Sporples 2018-10-09 20:12:12 -05:00
Sabe Jones 28ed9d8bcc fix(script): log, not warn, so all output goes to both stdout and tee 2018-10-09 20:27:52 +00:00
Matteo Pagliazzi 36ead77e0c Fixes group plan verify username (#10747)
Misc fixes
2018-10-09 20:07:50 +02:00
Robert Kojima e7969987ec Guild textarea at list positioning (#10663)
* autocomplete dialog now has ternary operator to determine placement

* added min height to textbox

* fixed spacing according to travisCI

* heightToUse function now retrieves argument from props
2018-10-08 22:25:49 +02:00
titchimoto 97021e3422 Issue 10414 - Remove Member Option from View Party link. (#10639)
* Add remove member option from main task page

* Code refactor for remove member options

* code refactor to avoid loading party multiple times

* fix dispatch to ensure only pulling once from server
2018-10-08 22:22:09 +02:00
Carl Vuorinen 218d47d64a Don't show "no guilds" texts while loading (#10665)
* Don't show "no guilds" texts while loading

Unified styling of "no guilds" message with my challenges page
Fixes #10662

* Don't show "no challenges" texts while loading

Add loading indicator (similar to find challenges & my guilds pages)

* Change gray color

* Set challenge icon color
2018-10-08 22:18:11 +02:00
Rene Cordier bdfc23717e Css font home page update (#10672)
* css font home page update

finish home page font change

* Small fixes on css font update on home page
2018-10-08 22:16:14 +02:00
Kirsty 464cd87736 Decrease mana when removing stat points from int (#10713)
* Decrease mana when removing stat points from int

* Revert "Decrease mana when removing stat points from int"

This reverts commit 5e25e13552.

* add mana when stat updates are saved

* don't allow users to deallocate saved stat points in the ui

* use flag to determine whether to add mana points

* add test for not adding mana points when flag is set

* Revert "add test for not adding mana points when flag is set"

This reverts commit 6e8ff36a79.

* Revert "use flag to determine whether to add mana points"

This reverts commit 274e2d0d33.

* Revert "add mana when stat updates are saved"

This reverts commit 422bd49191.

* move client side stat allocation to when save is pressed

* update displayed total stats during editing

* Fix lint errors
2018-10-08 22:11:26 +02:00
Kirsty 67a8eebb96 add errors for any param validation failures to the snackbar (#10724) 2018-10-08 21:54:05 +02:00
Kirsty cfc0f6a3ac remove items with that have been lost from Class:None (#10735) 2018-10-08 21:38:16 +02:00
Matteo Pagliazzi 9f76db12bd update aws-sdk, in-app-purchase, fix #10733 and #10725 2018-10-08 10:55:41 +02:00
Sabe Jones 70192e4935 Scripts October 2018 (#10741)
* chore(scripts): BTS Challenge archive and username email jobbing

* refactor(migration): use batching and sendTxn

* fix(script): introduce delay for batching

* fix(migration): correct import, fix delay promise, slower batching

* fix(migration): add daterange

* WIP(script): deletion helper for GDPR

* fix(script): address code comments

* refactor(script): use for loop

* fix(script-runner): bad catch syntax

* fix(script-runner): oops I did it again

* fix(lint): name functions
2018-10-07 14:20:30 -05:00
Sabe Jones 5cd4ead9d1 Merge branch 'release' into develop 2018-10-06 14:36:10 +00:00
Sabe Jones 87cd000bb8 4.64.2 2018-10-06 14:35:48 +00:00
Sabe Jones 0de5d8273b chore(i18n): update locales 2018-10-06 14:35:39 +00:00
Sabe Jones 379898cc4d fix(sprites): add new spritesheet to app manifest 2018-10-06 09:33:35 -05:00
Sabe Jones adeaa6c754 Merge branch 'release' into develop 2018-10-05 19:55:45 +00:00
Matteo Pagliazzi c880596a77 Cleanup after inbox migration (#10487) 2018-10-05 19:34:42 +02:00
Matteo Pagliazzi a35f04be46 migrations: move inbox migration to archive 2018-10-05 19:34:21 +02:00
negue 5632031f16 reload page if the user closes the modal or not clicking on the notification 2018-09-30 17:22:44 +02:00
negue 07bc374078 fix ultimate gear notification length - allow longer notifications but with a-like border-radius 2018-08-27 20:08:09 +02:00
negue c862bdb76a Merge branch 'develop' of https://github.com/HabitRPG/habitica into negue/modal-notifications
# Conflicts:
#	website/client/components/notifications.vue
2018-08-18 14:25:20 +02:00
negue b596576c53 rollback death modal changes 2018-08-18 14:22:16 +02:00
negue 9fd26a88ea Update notification.vue
remove duplicate methods props
2018-07-29 21:55:24 +02:00
negue 76860fe3f8 Merge branch 'develop' of https://github.com/HabitRPG/habitica into negue/modal-notifications
# Conflicts:
#	website/client/components/notifications.vue
2018-07-29 20:21:51 +02:00
negue b16e700de5 auto revive 2018-07-29 20:12:30 +02:00
negue b75e65f42d move modals to notifications (to open the modals) 2018-07-20 23:56:36 +02:00
490 changed files with 14886 additions and 13914 deletions
+1 -6
View File
@@ -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;
+9 -2
View File
@@ -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;
+1 -1
View File
@@ -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 });
+857 -1183
View File
File diff suppressed because it is too large Load Diff
+7 -8
View File
@@ -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",
+88
View File
@@ -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;
+8 -1
View File
@@ -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);
+30 -4
View File
@@ -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;
});
});
});
});
+33 -2
View File
@@ -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,
+1 -1
View File
@@ -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();
});
});
});
+21
View File
@@ -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);
}
}
});
});
+4 -13
View File
@@ -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;
}
File diff suppressed because it is too large Load Diff
@@ -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;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -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;
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 177 KiB

After

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 419 KiB

After

Width:  |  Height:  |  Size: 418 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 KiB

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 KiB

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 146 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 135 KiB

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 156 KiB

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 151 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 KiB

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

After

Width:  |  Height:  |  Size: 174 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 159 KiB

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

After

Width:  |  Height:  |  Size: 115 KiB

+1 -1
View File
@@ -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();
+4 -1
View File
@@ -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>
+16 -6
View File
@@ -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>
+22 -30
View File
@@ -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,
});
+5 -3
View File
@@ -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) {
+119 -40
View File
@@ -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) {
+6 -2
View File
@@ -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;
+23 -6
View File
@@ -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;
+1 -1
View File
@@ -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}}&nbsp;
| {{pointsRemaining}}&nbsp;
.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 () {
-1
View File
@@ -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)}`;
}
+20 -25
View File
@@ -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',
+3 -5
View File
@@ -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;
-2
View File
@@ -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;
}
-2
View File
@@ -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;
}
+1
View File
@@ -99,6 +99,7 @@
"noChallengeTitle": "Нямате никакви предизвикателства.",
"challengeDescription1": "Предизвикателствата са обществени събития, в които играчите се състезават и печелят награди като изпълняват няколко свързани по някакъв начин задачи.",
"challengeDescription2": "Открийте препоръчани за Вас предизвикателства според интересите Ви, разгледайте обществените предизвикателства на Хабитика, или създайте свои собствени предизвикателства.",
"noChallengeMatchFilters": "Не можем да открием съответстващи предизвикателства.",
"createdBy": "Създадено от",
"joinChallenge": "Присъединяване към предизвикателството",
"leaveChallenge": "Напускане на предизвикателството",
+1
View File
@@ -80,6 +80,7 @@
"autoEquipPopoverText": "Изберете това, за да екипирате всеки предмет в момента, когато го купите.",
"costumeDisabled": "Вие изключихте костюма си.",
"gearAchievement": "Вие спечелихте постижението „Последното снаряжение“ заради това, че достигнахте максималното снаряжение за класа си! Получавате следните пълни комплекти:",
"gearAchievementNotification": "Вие спечелихте постижението „Последното снаряжение“ заради това, че достигнахте максималното снаряжение за класа си!",
"moreGearAchievements": "За да получите още значки „Последното снаряжение“, променете класа си в <a href='/user/settings/site' target='_blank'>страницата „Настройки &gt; Уеб сайт</a> и купете екипировката на новия си клас!",
"armoireUnlocked": "За още екипировка, прегледайте <strong>Омагьосания гардероб!</strong> Щракнете наградата на Омагьосания гардероб и ще имате шанс да получите специална екипировка! Той може да Ви даде също опит или храна.",
"ultimGearName": "Последното снаряжение — <%= ultClass %>",
+3
View File
@@ -176,6 +176,9 @@
"questEggKangarooText": "Кенгуру",
"questEggKangarooMountText": "Кенгуру",
"questEggKangarooAdjective": "енергично",
"questEggAlligatorText": "Алигатор",
"questEggAlligatorMountText": "Алигатор",
"questEggAlligatorAdjective": "хитър",
"eggNotes": "Намерете излюпваща отвара, която да излеете върху това яйце и от него ще се излюпи <%= eggAdjective(locale) %> <%= eggText(locale) %>.",
"hatchingPotionBase": "Нормален цвят",
"hatchingPotionWhite": "Бял цвят",
+4
View File
@@ -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": "Обикновен цилиндър",
+4 -7
View File
@@ -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": "Създаване на група",
+1
View File
@@ -19,6 +19,7 @@
"veteranTiger": "Тигър ветеран",
"veteranLion": "Лъв ветеран",
"veteranBear": "Мечка ветеран",
"veteranFox": "Лисица ветеран",
"cerberusPup": "Кученце цербер",
"hydra": "Хидра",
"mantisShrimp": "Скарида-богомолка",
+7 -1
View File
@@ -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": "Изтънчен паунов комплект",
+1 -1
View File
@@ -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!"
+6 -6
View File
@@ -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."
}
+1
View File
@@ -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",
+2 -1
View File
@@ -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",
+4 -1
View File
@@ -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ý",

Some files were not shown because too many files have changed in this diff Show More