mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-10-30 12:44:45 +01:00
Compare commits
61 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b87527bcea | ||
|
|
0adfc9f756 | ||
|
|
9a2b49b4bf | ||
|
|
750a02053c | ||
|
|
2748455f16 | ||
|
|
cc0e807609 | ||
|
|
bbc5a54a3e | ||
|
|
8e717de039 | ||
|
|
ce18e614be | ||
|
|
58c27c2610 | ||
|
|
220dd51f85 | ||
|
|
3b1407f529 | ||
|
|
be7b3076eb | ||
|
|
2b4ffdf27f | ||
|
|
e0dc608fd8 | ||
|
|
0b4059aab0 | ||
|
|
3aa7b8b447 | ||
|
|
94b9bb1036 | ||
|
|
a2f169ab76 | ||
|
|
6d345740ff | ||
|
|
294cc63fef | ||
|
|
9a879d566e | ||
|
|
8ecb0f45b5 | ||
|
|
b04df06a37 | ||
|
|
706cffa71d | ||
|
|
00b8f4fef5 | ||
|
|
5ea675b8a5 | ||
|
|
78f0c71387 | ||
|
|
e674ef4035 | ||
|
|
1655e2e03a | ||
|
|
0d444a9d6a | ||
|
|
de331f5e76 | ||
|
|
c48043ec90 | ||
|
|
ac4d148170 | ||
|
|
ca49e995be | ||
|
|
d47a867149 | ||
|
|
f4d9c6271b | ||
|
|
0e458683fd | ||
|
|
76ab93f501 | ||
|
|
5d4600f5c7 | ||
|
|
13c4a726c7 | ||
|
|
43122805fb | ||
|
|
1262d8f36e | ||
|
|
2b1635ff62 | ||
|
|
e1664d2f87 | ||
|
|
6975b6061b | ||
|
|
695a5cc24d | ||
|
|
dcced2debb | ||
|
|
88af9c13a8 | ||
|
|
d5926ef7f1 | ||
|
|
e9222e4f7c | ||
|
|
cd0278c6b3 | ||
|
|
9680c94087 | ||
|
|
76de241675 | ||
|
|
3ba6b4a209 | ||
|
|
b101d43e62 | ||
|
|
c0e8d80966 | ||
|
|
afacd497d7 | ||
|
|
dc744de4a9 | ||
|
|
f44bebb573 | ||
|
|
8ccf701aec |
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"ACCOUNT_MIN_CHAT_AGE": "0",
|
||||
"ADMIN_EMAIL": "you@example.com",
|
||||
"AMAZON_PAYMENTS_CLIENT_ID": "CLIENT_ID",
|
||||
"AMAZON_PAYMENTS_MODE": "sandbox",
|
||||
|
||||
Submodule habitica-images updated: 847f56dd8f...58b8905b08
2168
package-lock.json
generated
2168
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@@ -1,19 +1,19 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
|
||||
"version": "4.234.1",
|
||||
"version": "4.237.0",
|
||||
"main": "./website/server/index.js",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.18.5",
|
||||
"@babel/preset-env": "^7.18.2",
|
||||
"@babel/register": "^7.17.7",
|
||||
"@babel/core": "^7.18.6",
|
||||
"@babel/preset-env": "^7.18.6",
|
||||
"@babel/register": "^7.18.6",
|
||||
"@google-cloud/trace-agent": "^5.1.6",
|
||||
"@parse/node-apn": "^5.1.3",
|
||||
"@slack/webhook": "^6.1.0",
|
||||
"accepts": "^1.3.8",
|
||||
"amazon-payments": "^0.2.9",
|
||||
"amplitude": "^6.0.0",
|
||||
"apidoc": "^0.51.1",
|
||||
"apidoc": "^0.52.0",
|
||||
"apple-auth": "^1.0.7",
|
||||
"bcrypt": "^5.0.1",
|
||||
"body-parser": "^1.20.0",
|
||||
@@ -39,7 +39,7 @@
|
||||
"gulp.spritesmith": "^6.13.0",
|
||||
"habitica-markdown": "^3.0.0",
|
||||
"helmet": "^4.6.0",
|
||||
"image-size": "^1.0.1",
|
||||
"image-size": "^1.0.2",
|
||||
"in-app-purchase": "^1.11.3",
|
||||
"js2xmlparser": "^4.0.2",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
@@ -47,7 +47,7 @@
|
||||
"lodash": "^4.17.21",
|
||||
"merge-stream": "^2.0.0",
|
||||
"method-override": "^3.0.0",
|
||||
"moment": "^2.29.3",
|
||||
"moment": "^2.29.4",
|
||||
"moment-recur": "^1.0.7",
|
||||
"mongoose": "^5.13.7",
|
||||
"morgan": "^1.10.0",
|
||||
@@ -74,7 +74,7 @@
|
||||
"uuid": "^8.3.2",
|
||||
"validator": "^13.7.0",
|
||||
"vinyl-buffer": "^1.0.1",
|
||||
"winston": "^3.7.2",
|
||||
"winston": "^3.8.1",
|
||||
"winston-loggly-bulk": "^3.2.1",
|
||||
"xml2js": "^0.4.23"
|
||||
},
|
||||
|
||||
@@ -15,6 +15,10 @@ describe('DELETE /groups/:groupId/chat/:chatId', () => {
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
},
|
||||
leaderDetails: {
|
||||
'auth.timestamps.created': new Date('2022-01-01'),
|
||||
balance: 10,
|
||||
},
|
||||
});
|
||||
|
||||
groupWithChat = group;
|
||||
|
||||
@@ -117,7 +117,9 @@ describe('POST /chat/:chatId/flag', () => {
|
||||
});
|
||||
|
||||
it('Flags a chat when the author\'s account was deleted', async () => {
|
||||
const deletedUser = await generateUser();
|
||||
const deletedUser = await generateUser({
|
||||
'auth.timestamps.created': new Date('2022-01-01'),
|
||||
});
|
||||
const { message } = await deletedUser.post(`/groups/${group._id}/chat`, { message: TEST_MESSAGE });
|
||||
await deletedUser.del('/user', {
|
||||
password: 'password',
|
||||
|
||||
@@ -18,11 +18,16 @@ describe('POST /chat/:chatId/like', () => {
|
||||
privacy: 'public',
|
||||
},
|
||||
members: 1,
|
||||
leaderDetails: {
|
||||
'auth.timestamps.created': new Date('2022-01-01'),
|
||||
balance: 10,
|
||||
},
|
||||
});
|
||||
|
||||
user = groupLeader;
|
||||
groupWithChat = group;
|
||||
anotherUser = members[0]; // eslint-disable-line prefer-destructuring
|
||||
await anotherUser.update({ 'auth.timestamps.created': new Date('2022-01-01') });
|
||||
});
|
||||
|
||||
it('Returns an error when chat message is not found', async () => {
|
||||
|
||||
@@ -38,10 +38,15 @@ describe('POST /chat', () => {
|
||||
members: 2,
|
||||
});
|
||||
user = groupLeader;
|
||||
await user.update({ 'contributor.level': SPAM_MIN_EXEMPT_CONTRIB_LEVEL }); // prevent tests accidentally throwing messageGroupChatSpam
|
||||
await user.update({
|
||||
'contributor.level': SPAM_MIN_EXEMPT_CONTRIB_LEVEL,
|
||||
'auth.timestamps.created': new Date('2022-01-01'),
|
||||
}); // prevent tests accidentally throwing messageGroupChatSpam
|
||||
groupWithChat = group;
|
||||
member = members[0]; // eslint-disable-line prefer-destructuring
|
||||
additionalMember = members[1]; // eslint-disable-line prefer-destructuring
|
||||
await member.update({ 'auth.timestamps.created': new Date('2022-01-01') });
|
||||
await additionalMember.update({ 'auth.timestamps.created': new Date('2022-01-01') });
|
||||
});
|
||||
|
||||
it('Returns an error when no message is provided', async () => {
|
||||
@@ -104,7 +109,10 @@ describe('POST /chat', () => {
|
||||
});
|
||||
|
||||
const privateGuildMemberWithChatsRevoked = members[0];
|
||||
await privateGuildMemberWithChatsRevoked.update({ 'flags.chatRevoked': true });
|
||||
await privateGuildMemberWithChatsRevoked.update({
|
||||
'flags.chatRevoked': true,
|
||||
'auth.timestamps.created': new Date('2022-01-01'),
|
||||
});
|
||||
|
||||
const message = await privateGuildMemberWithChatsRevoked.post(`/groups/${group._id}/chat`, { message: testMessage });
|
||||
|
||||
@@ -122,7 +130,10 @@ describe('POST /chat', () => {
|
||||
});
|
||||
|
||||
const privatePartyMemberWithChatsRevoked = members[0];
|
||||
await privatePartyMemberWithChatsRevoked.update({ 'flags.chatRevoked': true });
|
||||
await privatePartyMemberWithChatsRevoked.update({
|
||||
'flags.chatRevoked': true,
|
||||
'auth.timestamps.created': new Date('2022-01-01'),
|
||||
});
|
||||
|
||||
const message = await privatePartyMemberWithChatsRevoked.post(`/groups/${group._id}/chat`, { message: testMessage });
|
||||
|
||||
@@ -183,7 +194,10 @@ describe('POST /chat', () => {
|
||||
});
|
||||
|
||||
const userWithChatShadowMuted = members[0];
|
||||
await userWithChatShadowMuted.update({ 'flags.chatShadowMuted': true });
|
||||
await userWithChatShadowMuted.update({
|
||||
'flags.chatShadowMuted': true,
|
||||
'auth.timestamps.created': new Date('2022-01-01'),
|
||||
});
|
||||
|
||||
const message = await userWithChatShadowMuted.post(`/groups/${group._id}/chat`, { message: testMessage });
|
||||
|
||||
@@ -202,7 +216,10 @@ describe('POST /chat', () => {
|
||||
});
|
||||
|
||||
const userWithChatShadowMuted = members[0];
|
||||
await userWithChatShadowMuted.update({ 'flags.chatShadowMuted': true });
|
||||
await userWithChatShadowMuted.update({
|
||||
'flags.chatShadowMuted': true,
|
||||
'auth.timestamps.created': new Date('2022-01-01'),
|
||||
});
|
||||
|
||||
const message = await userWithChatShadowMuted.post(`/groups/${group._id}/chat`, { message: testMessage });
|
||||
|
||||
@@ -312,6 +329,7 @@ describe('POST /chat', () => {
|
||||
},
|
||||
members: 1,
|
||||
});
|
||||
await members[0].update({ 'auth.timestamps.created': new Date('2022-01-01') });
|
||||
|
||||
const message = await members[0].post(`/groups/${group._id}/chat`, { message: testBannedWordMessage });
|
||||
|
||||
@@ -330,6 +348,7 @@ describe('POST /chat', () => {
|
||||
|
||||
// Update the bannedWordsAllowed property for the group
|
||||
group.update({ bannedWordsAllowed: true });
|
||||
await members[0].update({ 'auth.timestamps.created': new Date('2022-01-01') });
|
||||
|
||||
const message = await members[0].post(`/groups/${group._id}/chat`, { message: testBannedWordMessage });
|
||||
|
||||
@@ -345,6 +364,7 @@ describe('POST /chat', () => {
|
||||
},
|
||||
members: 1,
|
||||
});
|
||||
await members[0].update({ 'auth.timestamps.created': new Date('2022-01-01') });
|
||||
|
||||
const message = await members[0].post(`/groups/${group._id}/chat`, { message: testBannedWordMessage });
|
||||
|
||||
@@ -411,6 +431,7 @@ describe('POST /chat', () => {
|
||||
},
|
||||
members: 1,
|
||||
});
|
||||
await members[0].update({ 'auth.timestamps.created': new Date('2022-01-01') });
|
||||
|
||||
const message = await members[0].post(`/groups/${group._id}/chat`, { message: testSlurMessage });
|
||||
|
||||
@@ -430,6 +451,16 @@ describe('POST /chat', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('errors when user account is too young', async () => {
|
||||
const brandNewUser = await generateUser();
|
||||
await expect(brandNewUser.post('/groups/habitrpg/chat', { message: 'hi im new' }))
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('chatTemporarilyUnavailable'),
|
||||
});
|
||||
});
|
||||
|
||||
it('creates a chat', async () => {
|
||||
const newMessage = await user.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
|
||||
const groupMessages = await user.get(`/groups/${groupWithChat._id}/chat`);
|
||||
@@ -492,6 +523,7 @@ describe('POST /chat', () => {
|
||||
'items.currentMount': mount,
|
||||
'items.currentPet': pet,
|
||||
'preferences.style': style,
|
||||
'auth.timestamps.created': new Date('2022-01-01'),
|
||||
});
|
||||
await userWithStyle.sync();
|
||||
|
||||
@@ -517,6 +549,7 @@ describe('POST /chat', () => {
|
||||
};
|
||||
const backer = await generateUser({
|
||||
backer: backerInfo,
|
||||
'auth.timestamps.created': new Date('2022-01-01'),
|
||||
});
|
||||
|
||||
const message = await backer.post(`/groups/${groupWithChat._id}/chat`, { message: testMessage });
|
||||
@@ -587,6 +620,9 @@ describe('POST /chat', () => {
|
||||
privacy: 'private',
|
||||
},
|
||||
members: 1,
|
||||
leaderDetails: {
|
||||
'auth.timestamps.created': new Date('2022-01-01'),
|
||||
},
|
||||
});
|
||||
|
||||
const message = await groupLeader.post(`/groups/${group._id}/chat`, { message: testMessage });
|
||||
|
||||
@@ -15,6 +15,10 @@ describe('POST /groups/:id/chat/seen', () => {
|
||||
privacy: 'public',
|
||||
},
|
||||
members: 1,
|
||||
leaderDetails: {
|
||||
'auth.timestamps.created': new Date('2022-01-01'),
|
||||
balance: 10,
|
||||
},
|
||||
});
|
||||
|
||||
guild = group;
|
||||
@@ -51,6 +55,9 @@ describe('POST /groups/:id/chat/seen', () => {
|
||||
privacy: 'private',
|
||||
},
|
||||
members: 1,
|
||||
leaderDetails: {
|
||||
'auth.timestamps.created': new Date('2022-01-01'),
|
||||
},
|
||||
});
|
||||
|
||||
party = group;
|
||||
|
||||
@@ -18,6 +18,10 @@ describe('POST /groups/:id/chat/:id/clearflags', () => {
|
||||
type: 'guild',
|
||||
privacy: 'public',
|
||||
},
|
||||
leaderDetails: {
|
||||
'auth.timestamps.created': new Date('2022-01-01'),
|
||||
balance: 10,
|
||||
},
|
||||
});
|
||||
|
||||
groupWithChat = group;
|
||||
@@ -65,6 +69,7 @@ describe('POST /groups/:id/chat/:id/clearflags', () => {
|
||||
members: 1,
|
||||
});
|
||||
|
||||
await members[0].update({ 'auth.timestamps.created': new Date('2022-01-01') });
|
||||
let privateMessage = await members[0].post(`/groups/${group._id}/chat`, { message: 'Some message' });
|
||||
privateMessage = privateMessage.message;
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ describe('POST /groups/:groupId/leave', () => {
|
||||
leader = groupLeader;
|
||||
member = members[0]; // eslint-disable-line prefer-destructuring
|
||||
memberCount = group.memberCount;
|
||||
await members[0].update({ 'auth.timestamps.created': new Date('2022-01-01') });
|
||||
});
|
||||
|
||||
it('prevents non members from leaving', async () => {
|
||||
@@ -152,6 +153,10 @@ describe('POST /groups/:groupId/leave', () => {
|
||||
type: 'guild',
|
||||
},
|
||||
invites: 1,
|
||||
leaderDetails: {
|
||||
'auth.timestamps.created': new Date('2022-01-01'),
|
||||
balance: 10,
|
||||
},
|
||||
});
|
||||
|
||||
privateGuild = group;
|
||||
|
||||
@@ -153,6 +153,7 @@ describe('POST /groups/:groupId/removeMember/:memberId', () => {
|
||||
},
|
||||
invites: 1,
|
||||
members: 2,
|
||||
leaderDetails: { 'auth.timestamps.created': new Date('2022-01-01') },
|
||||
});
|
||||
|
||||
party = group;
|
||||
|
||||
@@ -25,6 +25,7 @@ describe('Prevent multiple notifications', () => {
|
||||
|
||||
for (let i = 0; i < 4; i += 1) {
|
||||
for (let memberIndex = 0; memberIndex < partyMembers.length; memberIndex += 1) {
|
||||
await partyMembers[memberIndex].update({ 'auth.timestamps.created': new Date('2022-01-01') }); // eslint-disable-line no-await-in-loop
|
||||
multipleChatMessages.push(
|
||||
partyMembers[memberIndex].post(`/groups/${party._id}/chat`, { message: `Message ${i}_${memberIndex}` }),
|
||||
);
|
||||
|
||||
@@ -39,25 +39,38 @@ describe('POST /user/buy-quest/:key', () => {
|
||||
}));
|
||||
});
|
||||
|
||||
it('returns an error if quest prerequisites are not met', async () => {
|
||||
const key = 'dilatoryDistress2';
|
||||
it('returns an error if not all quest prerequisites are met', async () => {
|
||||
const prerequisites = ['dilatoryDistress1', 'dilatoryDistress2'];
|
||||
const key = 'dilatoryDistress3';
|
||||
|
||||
const achievementName1 = `achievements.quests.${prerequisites[0]}`;
|
||||
|
||||
await user.update({
|
||||
[achievementName1]: true,
|
||||
'stats.gp': 9999,
|
||||
});
|
||||
|
||||
await expect(user.post(`/user/buy-quest/${key}`))
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: t('mustComplete', { quest: 'dilatoryDistress1' }),
|
||||
message: t('mustComplete', { quest: prerequisites[1] }),
|
||||
});
|
||||
});
|
||||
|
||||
it('allows purchase of a quest if prerequisites are met', async () => {
|
||||
const prerequisite = 'dilatoryDistress1';
|
||||
const key = 'dilatoryDistress2';
|
||||
const prerequisites = ['dilatoryDistress1', 'dilatoryDistress2'];
|
||||
const key = 'dilatoryDistress3';
|
||||
const item = content.quests[key];
|
||||
|
||||
const achievementName = `achievements.quests.${prerequisite}`;
|
||||
const achievementName1 = `achievements.quests.${prerequisites[0]}`;
|
||||
const achievementName2 = `achievements.quests.${prerequisites[1]}`;
|
||||
|
||||
await user.update({ [achievementName]: true, 'stats.gp': 9999 });
|
||||
await user.update({
|
||||
[achievementName1]: true,
|
||||
[achievementName2]: true,
|
||||
'stats.gp': 9999,
|
||||
});
|
||||
const res = await user.post(`/user/buy-quest/${key}`);
|
||||
await user.sync();
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ describe('shared.ops.buyQuestGems', () => {
|
||||
pinnedGearUtils.removeItemByPath.restore();
|
||||
});
|
||||
|
||||
context('successful purchase', () => {
|
||||
context('single purchase', () => {
|
||||
const userGemAmount = 10;
|
||||
|
||||
before(() => {
|
||||
@@ -44,7 +44,7 @@ describe('shared.ops.buyQuestGems', () => {
|
||||
user.pinnedItems.push({ type: 'quests', key: 'gryphon' });
|
||||
});
|
||||
|
||||
it('purchases quests', async () => {
|
||||
it('successfully purchases quest', async () => {
|
||||
const key = 'gryphon';
|
||||
|
||||
await buyQuest(user, { params: { key } });
|
||||
@@ -58,6 +58,28 @@ describe('shared.ops.buyQuestGems', () => {
|
||||
|
||||
await buyQuest(user, { params: { key } });
|
||||
|
||||
expect(user.items.quests[key]).to.equal(1);
|
||||
expect(pinnedGearUtils.removeItemByPath.notCalled).to.equal(true);
|
||||
});
|
||||
it('errors if the user has not completed prerequisite quests', async () => {
|
||||
const key = 'atom3';
|
||||
user.achievements.quests.atom1 = 1;
|
||||
|
||||
try {
|
||||
await buyQuest(user, { params: { key } });
|
||||
} catch (err) {
|
||||
expect(err).to.be.an.instanceof(NotAuthorized);
|
||||
expect(err.message).to.equal(i18n.t('mustComplete', { quest: 'atom2' }));
|
||||
expect(user.items.quests[key]).to.eql(undefined);
|
||||
}
|
||||
});
|
||||
it('successfully purchases quest if user has completed all prerequisite quests', async () => {
|
||||
const key = 'atom3';
|
||||
user.achievements.quests.atom1 = 1;
|
||||
user.achievements.quests.atom2 = 1;
|
||||
|
||||
await buyQuest(user, { params: { key } });
|
||||
|
||||
expect(user.items.quests[key]).to.equal(1);
|
||||
expect(pinnedGearUtils.removeItemByPath.notCalled).to.equal(true);
|
||||
});
|
||||
|
||||
@@ -162,7 +162,9 @@ describe('shared.ops.buyQuest', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('does not buy a quest without completing previous quests', async () => {
|
||||
it('returns error if user has not completed all prerequisite quests', async () => {
|
||||
user.stats.gp = 9999;
|
||||
user.achievements.quests.dilatoryDistress1 = 1;
|
||||
try {
|
||||
await buyQuest(user, {
|
||||
params: {
|
||||
@@ -175,4 +177,22 @@ describe('shared.ops.buyQuest', () => {
|
||||
expect(user.items.quests).to.eql({});
|
||||
}
|
||||
});
|
||||
|
||||
it('successfully purchases quest if user has completed all prerequisite quests', async () => {
|
||||
user.stats.gp = 500;
|
||||
user.achievements.quests.dilatoryDistress1 = 1;
|
||||
user.achievements.quests.dilatoryDistress2 = 1;
|
||||
|
||||
await buyQuest(user, {
|
||||
params: {
|
||||
key: 'dilatoryDistress3',
|
||||
},
|
||||
}, analytics);
|
||||
|
||||
expect(user.items.quests).to.eql({
|
||||
dilatoryDistress3: 1,
|
||||
});
|
||||
expect(user.stats.gp).to.equal(100);
|
||||
expect(analytics.track).to.be.calledOnce;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,6 +11,7 @@ if (process.env.LOAD_SERVER === '0') { // when the server is in a different proc
|
||||
setupNconf('./config.json.example');
|
||||
nconf.set('NODE_DB_URI', nconf.get('TEST_DB_URI'));
|
||||
nconf.set('NODE_ENV', 'test');
|
||||
nconf.set('ACCOUNT_MIN_CHAT_AGE', '2');
|
||||
nconf.set('IS_TEST', true);
|
||||
// We require src/server and not src/index because
|
||||
// 1. nconf is already setup
|
||||
|
||||
120
website/client/package-lock.json
generated
120
website/client/package-lock.json
generated
@@ -22,9 +22,9 @@
|
||||
}
|
||||
},
|
||||
"@amplitude/analytics-connector": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/@amplitude/analytics-connector/-/analytics-connector-1.4.3.tgz",
|
||||
"integrity": "sha512-Ghu1UJn55Rn9eglF+ED7yOGXaeX3KY2qkQi9W9yqC02ItPvKfrybeVndweI1XtsiW0LvRpdA3uQEjuZEGunyLw==",
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@amplitude/analytics-connector/-/analytics-connector-1.4.4.tgz",
|
||||
"integrity": "sha512-6JcE1nxrprJt6pHqqDQb7FXRqJmFHG7KJPe0jNZaAvfll4mWKVqZu8W9IV3XiN1P+xgHIV1NN+i3PLOAZWEhXg==",
|
||||
"requires": {
|
||||
"@amplitude/ua-parser-js": "0.7.31"
|
||||
}
|
||||
@@ -1799,39 +1799,39 @@
|
||||
}
|
||||
},
|
||||
"@babel/plugin-proposal-optional-chaining": {
|
||||
"version": "7.17.12",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.17.12.tgz",
|
||||
"integrity": "sha512-7wigcOs/Z4YWlK7xxjkvaIw84vGhDv/P1dFGQap0nHkc8gFKY/r+hXc8Qzf5k1gY7CvGIcHqAnOagVKJJ1wVOQ==",
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.6.tgz",
|
||||
"integrity": "sha512-PatI6elL5eMzoypFAiYDpYQyMtXTn+iMhuxxQt5mAXD4fEmKorpSI3PHd+i3JXBJN3xyA6MvJv7at23HffFHwA==",
|
||||
"requires": {
|
||||
"@babel/helper-plugin-utils": "^7.17.12",
|
||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.16.0",
|
||||
"@babel/helper-plugin-utils": "^7.18.6",
|
||||
"@babel/helper-skip-transparent-expression-wrappers": "^7.18.6",
|
||||
"@babel/plugin-syntax-optional-chaining": "^7.8.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": {
|
||||
"version": "7.17.12",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz",
|
||||
"integrity": "sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA=="
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz",
|
||||
"integrity": "sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg=="
|
||||
},
|
||||
"@babel/helper-skip-transparent-expression-wrappers": {
|
||||
"version": "7.16.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz",
|
||||
"integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==",
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.6.tgz",
|
||||
"integrity": "sha512-4KoLhwGS9vGethZpAhYnMejWkX64wsnHPDwvOsKWU6Fg4+AlK2Jz3TyjQLMEPvz+1zemi/WBdkYxCD0bAfIkiw==",
|
||||
"requires": {
|
||||
"@babel/types": "^7.16.0"
|
||||
"@babel/types": "^7.18.6"
|
||||
}
|
||||
},
|
||||
"@babel/helper-validator-identifier": {
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz",
|
||||
"integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw=="
|
||||
"version": "7.18.6",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz",
|
||||
"integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g=="
|
||||
},
|
||||
"@babel/types": {
|
||||
"version": "7.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.0.tgz",
|
||||
"integrity": "sha512-vhAmLPAiC8j9K2GnsnLPCIH5wCrPpYIVBCWRBFDCB7Y/BXLqi/O+1RSTTM2bsmg6U/551+FCf9PNPxjABmxHTw==",
|
||||
"version": "7.18.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.7.tgz",
|
||||
"integrity": "sha512-QG3yxTcTIBoAcQmkCs+wAPYZhu7Dk9rXKacINfNbdJDNERTbLQbHGyVG8q/YGMPeCJRIhSY0+fTc5+xuh6WPSQ==",
|
||||
"requires": {
|
||||
"@babel/helper-validator-identifier": "^7.16.7",
|
||||
"@babel/helper-validator-identifier": "^7.18.6",
|
||||
"to-fast-properties": "^2.0.0"
|
||||
}
|
||||
}
|
||||
@@ -12131,11 +12131,11 @@
|
||||
}
|
||||
},
|
||||
"@vue/cli-plugin-eslint": {
|
||||
"version": "4.5.17",
|
||||
"resolved": "https://registry.npmjs.org/@vue/cli-plugin-eslint/-/cli-plugin-eslint-4.5.17.tgz",
|
||||
"integrity": "sha512-bVNDP+SuWcuJrBMc+JLaKvlxx25XKIlZBa+zzFnxhHZlwPZ7CeBD3e2wnsygJyPoKgDZcZwDgmEz1BZzMEjsNw==",
|
||||
"version": "4.5.19",
|
||||
"resolved": "https://registry.npmjs.org/@vue/cli-plugin-eslint/-/cli-plugin-eslint-4.5.19.tgz",
|
||||
"integrity": "sha512-53sa4Pu9j5KajesFlj494CcO8vVo3e3nnZ1CCKjGGnrF90id1rUeepcFfz5XjwfEtbJZp2x/NoX/EZE6zCzSFQ==",
|
||||
"requires": {
|
||||
"@vue/cli-shared-utils": "^4.5.17",
|
||||
"@vue/cli-shared-utils": "^4.5.19",
|
||||
"eslint-loader": "^2.2.1",
|
||||
"globby": "^9.2.0",
|
||||
"inquirer": "^7.1.0",
|
||||
@@ -12144,9 +12144,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@vue/cli-shared-utils": {
|
||||
"version": "4.5.17",
|
||||
"resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-4.5.17.tgz",
|
||||
"integrity": "sha512-VoFNdxvTW4vZu3ne+j1Mf7mU99J2SAoRVn9XPrsouTUUJablglM8DASk7Ixhsh6ymyL/W9EADQFR6Pgj8Ujjuw==",
|
||||
"version": "4.5.19",
|
||||
"resolved": "https://registry.npmjs.org/@vue/cli-shared-utils/-/cli-shared-utils-4.5.19.tgz",
|
||||
"integrity": "sha512-JYpdsrC/d9elerKxbEUtmSSU6QRM60rirVubOewECHkBHj+tLNznWq/EhCjswywtePyLaMUK25eTqnTSZlEE+g==",
|
||||
"requires": {
|
||||
"@achrinza/node-ipc": "9.2.2",
|
||||
"@hapi/joi": "^15.0.1",
|
||||
@@ -13086,11 +13086,11 @@
|
||||
"integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM="
|
||||
},
|
||||
"amplitude-js": {
|
||||
"version": "8.18.4",
|
||||
"resolved": "https://registry.npmjs.org/amplitude-js/-/amplitude-js-8.18.4.tgz",
|
||||
"integrity": "sha512-Nk4ymaw9iGf1Be/fGuuH7H/QnUJceD2RYGdode8ZAApw6jHlm9QZCoYoVRrNPdgfb3yJz3P84EPh/4xM+/98/w==",
|
||||
"version": "8.18.5",
|
||||
"resolved": "https://registry.npmjs.org/amplitude-js/-/amplitude-js-8.18.5.tgz",
|
||||
"integrity": "sha512-s43q4qKd7kvhYESQhYvyKDKUM1PpyAyoOFFlyMuFfQHRxyeDmZRhcfzrKnOhbrLhFxSWtPc0VEeh9tajJRNe5Q==",
|
||||
"requires": {
|
||||
"@amplitude/analytics-connector": "1.4.3",
|
||||
"@amplitude/analytics-connector": "1.4.4",
|
||||
"@amplitude/ua-parser-js": "0.7.31",
|
||||
"@amplitude/utils": "^1.0.5",
|
||||
"@babel/runtime": "^7.3.4",
|
||||
@@ -13697,9 +13697,12 @@
|
||||
"integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg=="
|
||||
},
|
||||
"async": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz",
|
||||
"integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g=="
|
||||
"version": "2.6.4",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
|
||||
"integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
|
||||
"requires": {
|
||||
"lodash": "^4.17.14"
|
||||
}
|
||||
},
|
||||
"async-each": {
|
||||
"version": "1.0.3",
|
||||
@@ -15836,9 +15839,9 @@
|
||||
}
|
||||
},
|
||||
"core-js": {
|
||||
"version": "3.22.8",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.22.8.tgz",
|
||||
"integrity": "sha512-UoGQ/cfzGYIuiq6Z7vWL1HfkE9U9IZ4Ub+0XSiJTCzvbZzgPA69oDF2f+lgJ6dFFLEdjW5O6svvoKzXX23xFkA=="
|
||||
"version": "3.23.5",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.23.5.tgz",
|
||||
"integrity": "sha512-7Vh11tujtAZy82da4duVreQysIoO2EvVrur7y6IzZkH1IHPSekuDi8Vuw1+YKjkbfWLRD7Nc9ICQ/sIUDutcyg=="
|
||||
},
|
||||
"core-js-compat": {
|
||||
"version": "3.11.0",
|
||||
@@ -20975,7 +20978,7 @@
|
||||
"find-cache-dir": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz",
|
||||
"integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=",
|
||||
"integrity": "sha512-Z9XSBoNE7xQiV6MSgPuCfyMokH2K7JdpRkOYE1+mu3d4BFJtx3GW+f6Bo4q8IX6rlf5MYbLBKW0pjl2cWdkm2A==",
|
||||
"requires": {
|
||||
"commondir": "^1.0.1",
|
||||
"mkdirp": "^0.5.1",
|
||||
@@ -20985,7 +20988,7 @@
|
||||
"find-up": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
|
||||
"integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
|
||||
"integrity": "sha512-jvElSjyuo4EMQGoTwo1uJU5pQMwTW5lS1x05zzfJuTIyLR3zwO27LYrxNg+dlvKpGOuGy/MzBdXh80g0ve5+HA==",
|
||||
"requires": {
|
||||
"path-exists": "^2.0.0",
|
||||
"pinkie-promise": "^2.0.0"
|
||||
@@ -20994,7 +20997,7 @@
|
||||
"path-exists": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
|
||||
"integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
|
||||
"integrity": "sha512-yTltuKuhtNeFJKa1PiRzfLAU5182q1y4Eb4XCJ3PBqyzEDkAZRzBrKKBct682ls9reBVHf9udYLN5Nd+K1B9BQ==",
|
||||
"requires": {
|
||||
"pinkie-promise": "^2.0.0"
|
||||
}
|
||||
@@ -21002,7 +21005,7 @@
|
||||
"pkg-dir": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz",
|
||||
"integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=",
|
||||
"integrity": "sha512-c6pv3OE78mcZ92ckebVDqg0aWSoKhOTbwCV6qbCWMk546mAL9pZln0+QsN/yQ7fkucd4+yJPLrCBXNt8Ruk+Eg==",
|
||||
"requires": {
|
||||
"find-up": "^1.0.0"
|
||||
}
|
||||
@@ -21926,9 +21929,9 @@
|
||||
}
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.29.3",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.3.tgz",
|
||||
"integrity": "sha512-c6YRvhEo//6T2Jz/vVtYzqBzwvPT95JBQ+smCytzf7c50oMZRsR/a4w88aD34I+/QVSfnoAnSBFPJHItlOMJVw=="
|
||||
"version": "2.29.4",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
|
||||
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="
|
||||
},
|
||||
"move-concurrently": {
|
||||
"version": "1.0.1",
|
||||
@@ -22035,6 +22038,11 @@
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"async": {
|
||||
"version": "3.2.4",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
|
||||
"integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ=="
|
||||
},
|
||||
"cliui": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
|
||||
@@ -23119,14 +23127,6 @@
|
||||
"mkdirp": "^0.5.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"async": {
|
||||
"version": "2.6.3",
|
||||
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
|
||||
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
|
||||
"requires": {
|
||||
"lodash": "^4.17.14"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
|
||||
@@ -26883,7 +26883,7 @@
|
||||
"strip-indent": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-2.0.0.tgz",
|
||||
"integrity": "sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g="
|
||||
"integrity": "sha512-RsSNPLpq6YUL7QYy44RnPVTn/lcVZtb48Uof3X5JLbF4zD/Gs7ZFDv2HWol+leoQN2mT86LAzSshGfkTlSOpsA=="
|
||||
},
|
||||
"strip-json-comments": {
|
||||
"version": "2.0.1",
|
||||
@@ -29477,7 +29477,7 @@
|
||||
"cross-spawn": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
|
||||
"integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
|
||||
"integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==",
|
||||
"requires": {
|
||||
"lru-cache": "^4.0.1",
|
||||
"shebang-command": "^1.2.0",
|
||||
@@ -29487,7 +29487,7 @@
|
||||
"execa": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/execa/-/execa-0.8.0.tgz",
|
||||
"integrity": "sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=",
|
||||
"integrity": "sha512-zDWS+Rb1E8BlqqhALSt9kUhss8Qq4nN3iof3gsOdyINksElaPyNBtKUMTR62qhvgVWR0CqCX7sdnKe4MnUbFEA==",
|
||||
"requires": {
|
||||
"cross-spawn": "^5.0.1",
|
||||
"get-stream": "^3.0.0",
|
||||
@@ -29501,7 +29501,7 @@
|
||||
"get-stream": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
|
||||
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
|
||||
"integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ=="
|
||||
},
|
||||
"lru-cache": {
|
||||
"version": "4.1.5",
|
||||
@@ -29515,12 +29515,12 @@
|
||||
"normalize-path": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-1.0.0.tgz",
|
||||
"integrity": "sha1-MtDkcvkf80VwHBWoMRAY07CpA3k="
|
||||
"integrity": "sha512-7WyT0w8jhpDStXRq5836AMmihQwq2nrUVQrgjvUo/p/NZf9uy/MeJ246lBJVmWuYXMlJuG9BNZHF0hWjfTbQUA=="
|
||||
},
|
||||
"yallist": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
|
||||
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
|
||||
"integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -20,19 +20,19 @@
|
||||
"@storybook/addons": "6.5.9",
|
||||
"@storybook/vue": "6.3.13",
|
||||
"@vue/cli-plugin-babel": "^4.5.15",
|
||||
"@vue/cli-plugin-eslint": "^4.5.17",
|
||||
"@vue/cli-plugin-eslint": "^4.5.19",
|
||||
"@vue/cli-plugin-router": "^4.5.15",
|
||||
"@vue/cli-plugin-unit-mocha": "^4.5.15",
|
||||
"@vue/cli-service": "^4.5.15",
|
||||
"@vue/test-utils": "1.0.0-beta.29",
|
||||
"amplitude-js": "^8.18.4",
|
||||
"amplitude-js": "^8.18.5",
|
||||
"axios": "^0.25.0",
|
||||
"axios-progress-bar": "^1.2.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"bootstrap": "^4.6.0",
|
||||
"bootstrap-vue": "^2.22.0",
|
||||
"chai": "^4.3.6",
|
||||
"core-js": "^3.22.8",
|
||||
"core-js": "^3.23.5",
|
||||
"dompurify": "^2.3.8",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-habitrpg": "^6.2.0",
|
||||
@@ -44,7 +44,7 @@
|
||||
"intro.js": "^5.1.0",
|
||||
"jquery": "^3.6.0",
|
||||
"lodash": "^4.17.21",
|
||||
"moment": "^2.29.3",
|
||||
"moment": "^2.29.4",
|
||||
"nconf": "^0.12.0",
|
||||
"sass": "^1.34.0",
|
||||
"sass-loader": "^8.0.2",
|
||||
@@ -65,6 +65,6 @@
|
||||
"webpack": "^4.46.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.17.12"
|
||||
"@babel/plugin-proposal-optional-chaining": "^7.18.6"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,7 +414,15 @@ export default {
|
||||
this.$store.state.isUserLoaded = true;
|
||||
Analytics.setUser();
|
||||
Analytics.updateUser();
|
||||
return axios.get('/api/v4/i18n/browser-script', { language: this.user.preferences.language });
|
||||
return axios.get('/api/v4/i18n/browser-script',
|
||||
{
|
||||
language: this.user.preferences.language,
|
||||
headers: {
|
||||
'Cache-Control': 'no-cache',
|
||||
Pragma: 'no-cache',
|
||||
Expires: '0',
|
||||
},
|
||||
});
|
||||
}).then(() => {
|
||||
const i18nData = window && window['habitica-i18n'];
|
||||
this.$loadLocale(i18nData);
|
||||
|
||||
@@ -625,6 +625,11 @@
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_bioluminescent_waves {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_bioluminescent_waves.png');
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_birch_forest {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_birch_forest.png');
|
||||
width: 141px;
|
||||
@@ -1884,11 +1889,21 @@
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_underwater_cave {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_underwater_cave.png');
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_underwater_ruins {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_underwater_ruins.png');
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_underwater_statues {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_underwater_statues.png');
|
||||
width: 141px;
|
||||
height: 147px;
|
||||
}
|
||||
.background_underwater_vents {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_underwater_vents.png');
|
||||
width: 141px;
|
||||
@@ -2151,6 +2166,11 @@
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.icon_background_bioluminescent_waves {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_bioluminescent_waves.png');
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.icon_background_birch_forest {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_birch_forest.png');
|
||||
width: 68px;
|
||||
@@ -3420,11 +3440,21 @@
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.icon_background_underwater_cave {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_underwater_cave.png');
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.icon_background_underwater_ruins {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_underwater_ruins.png');
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.icon_background_underwater_statues {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_underwater_statues.png');
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.icon_background_underwater_vents {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_underwater_vents.png');
|
||||
width: 68px;
|
||||
@@ -18145,6 +18175,11 @@
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_armoire_fancyPirateSuit {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_fancyPirateSuit.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.broad_armor_armoire_farrierOutfit {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_armoire_farrierOutfit.png');
|
||||
width: 90px;
|
||||
@@ -18590,6 +18625,11 @@
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_armoire_fancyPirateHat {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_fancyPirateHat.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.head_armoire_fiddlersCap {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_armoire_fiddlersCap.png');
|
||||
width: 114px;
|
||||
@@ -19175,6 +19215,11 @@
|
||||
width: 114px;
|
||||
height: 87px;
|
||||
}
|
||||
.shield_armoire_treasureMap {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_armoire_treasureMap.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.shield_armoire_trustyUmbrella {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_armoire_trustyUmbrella.png');
|
||||
width: 114px;
|
||||
@@ -19325,6 +19370,11 @@
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.shop_armor_armoire_fancyPirateSuit {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_armor_armoire_fancyPirateSuit.png');
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.shop_armor_armoire_farrierOutfit {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_armor_armoire_farrierOutfit.png');
|
||||
width: 68px;
|
||||
@@ -19785,6 +19835,11 @@
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.shop_head_armoire_fancyPirateHat {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_head_armoire_fancyPirateHat.png');
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.shop_head_armoire_fiddlersCap {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_head_armoire_fiddlersCap.png');
|
||||
width: 68px;
|
||||
@@ -20370,6 +20425,11 @@
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.shop_shield_armoire_treasureMap {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_shield_armoire_treasureMap.png');
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.shop_shield_armoire_trustyUmbrella {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_shield_armoire_trustyUmbrella.png');
|
||||
width: 68px;
|
||||
@@ -20960,6 +21020,11 @@
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_armoire_fancyPirateSuit {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_fancyPirateSuit.png');
|
||||
width: 114px;
|
||||
height: 90px;
|
||||
}
|
||||
.slim_armor_armoire_farrierOutfit {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_armoire_farrierOutfit.png');
|
||||
width: 90px;
|
||||
@@ -26830,6 +26895,36 @@
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.broad_armor_mystery_202207 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_mystery_202207.png');
|
||||
width: 117px;
|
||||
height: 120px;
|
||||
}
|
||||
.head_mystery_202207 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_mystery_202207.png');
|
||||
width: 117px;
|
||||
height: 120px;
|
||||
}
|
||||
.shop_armor_mystery_202207 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_armor_mystery_202207.png');
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.shop_head_mystery_202207 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_head_mystery_202207.png');
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.shop_set_mystery_202207 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_set_mystery_202207.png');
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
}
|
||||
.slim_armor_mystery_202207 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/slim_armor_mystery_202207.png');
|
||||
width: 117px;
|
||||
height: 120px;
|
||||
}
|
||||
.broad_armor_mystery_301404 {
|
||||
background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_mystery_301404.png');
|
||||
width: 90px;
|
||||
|
||||
@@ -82,7 +82,7 @@ input, textarea, input.form-control, textarea.form-control {
|
||||
}
|
||||
}
|
||||
|
||||
/** Colored Input-Groups, ignoring checklist */
|
||||
// Colored Input-Groups, ignoring checklist
|
||||
.input-group:not(.checklist-group) {
|
||||
border-radius: 2px;
|
||||
border: solid 1px $gray-400;
|
||||
@@ -100,7 +100,7 @@ input, textarea, input.form-control, textarea.form-control {
|
||||
}
|
||||
}
|
||||
|
||||
/** Generic Input Group Styles */
|
||||
// Generic Input Group Styles
|
||||
.input-group {
|
||||
height: 2rem;
|
||||
|
||||
@@ -179,10 +179,11 @@ input, textarea, input.form-control, textarea.form-control {
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
// Checkboxes and radios
|
||||
// used in checkboxes and radios
|
||||
$bg-focused-active-control: #4f2993;
|
||||
$bg-disabled-control: #34303a;
|
||||
|
||||
// custom control
|
||||
.custom-control {
|
||||
margin-bottom: .5rem;
|
||||
|
||||
@@ -205,6 +206,7 @@ $bg-disabled-control: #34303a;
|
||||
}
|
||||
}
|
||||
|
||||
// checkboxes
|
||||
.custom-checkbox {
|
||||
.custom-control-label::before {
|
||||
border-radius: 2px;
|
||||
@@ -280,11 +282,26 @@ $bg-disabled-control: #34303a;
|
||||
padding-left: 36px;
|
||||
}
|
||||
|
||||
// radio buttons
|
||||
$bg-color: $purple-400;
|
||||
|
||||
// svg for the purple dot
|
||||
@mixin custom-radio-checked-icon ($bg-color) {
|
||||
background-image: str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3E%3Ccircle r='3' fill='#{$bg-color}'/%3E%3C/svg%3E"), "#", "%23");
|
||||
}
|
||||
|
||||
.custom-radio .custom-control-input {
|
||||
opacity: 0;
|
||||
margin: 15px 25px 34px 25px;
|
||||
|
||||
// outside circle
|
||||
&:checked~.custom-control-label::before {
|
||||
background-color: $gray-700;
|
||||
background-size: 12px 12px;
|
||||
border-color: $purple-400;
|
||||
}
|
||||
|
||||
// checked indicator
|
||||
&:checked~.custom-control-label::after {
|
||||
@include custom-radio-checked-icon($purple-400);
|
||||
width: 18px;
|
||||
@@ -292,51 +309,84 @@ $bg-disabled-control: #34303a;
|
||||
background-size: 12px 12px;
|
||||
}
|
||||
|
||||
&:checked~.custom-control-label::before {
|
||||
background-color: $gray-700;
|
||||
background-size: 12px 12px;
|
||||
border-color: $purple-400;
|
||||
}
|
||||
|
||||
&:active~.custom-control-label::before {
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
&:focus:not(:checked):not(:disabled)~.custom-control-label::before, &:active:not(:checked):not(:disabled)~.custom-control-label::before {
|
||||
box-shadow: 0 0 0 6px rgba($bg-focused-active-control, 0.1);
|
||||
// focus / not checked / not disabled
|
||||
&:focus:not(:checked):not(:disabled)~.custom-control-label::before,
|
||||
&:active:not(:checked):not(:disabled)~.custom-control-label::before {
|
||||
border: 2px solid $gray-300;
|
||||
box-shadow: 0 0 0 2px rgba(146, 92, 243, 0.5);
|
||||
}
|
||||
|
||||
&:focus:checked:not(:disabled)~.custom-control-label::before, &:active:checked:not(:disabled)~.custom-control-label::before {
|
||||
box-shadow: 0 0 0 6px rgba($bg-focused-active-control, 0.1);
|
||||
border-color: $purple-400;
|
||||
background-color: rgba($bg-focused-active-control, 0.1);
|
||||
// focus / checked / not disabled
|
||||
&:focus:checked:not(:disabled)~.custom-control-label::before,
|
||||
&:active:checked:not(:disabled)~.custom-control-label::before {
|
||||
border: 2px solid $purple-400;
|
||||
box-shadow: 0 0 0 2px rgba(146, 92, 243, 0.5);
|
||||
}
|
||||
|
||||
&:disabled:checked~.custom-control-label::before {
|
||||
border-color: $gray-400;
|
||||
background-color: transparent;
|
||||
// hover / not checked / not disabled
|
||||
&:hover:not(:checked):not(:disabled)~.custom-control-label::before,
|
||||
&:active:not(:checked):not(:disabled)~.custom-control-label::before {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: 50%/50% 50% no-repeat;
|
||||
@include custom-radio-checked-icon($purple-400);
|
||||
background-size: 12px 12px;
|
||||
border: solid 2px $purple-400;
|
||||
}
|
||||
|
||||
&:disabled:checked~.custom-control-label::after {
|
||||
// hover / checked / not disabled
|
||||
&:hover:checked:not(:disabled)~.custom-control-label::before,
|
||||
&:active::checked:not(:disabled)~.custom-control-label::before {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background: 50%/50% 50% no-repeat;
|
||||
@include custom-radio-checked-icon($gray-400);
|
||||
background-size: 12px 12px;
|
||||
border: solid 2px $purple-300;
|
||||
}
|
||||
|
||||
// disabled / checked / before
|
||||
&:disabled:checked~.custom-control-label::before {
|
||||
background: 50%/50% 50% no-repeat;
|
||||
@include custom-radio-checked-icon($gray-300);
|
||||
border: 2px solid $gray-200;
|
||||
background-color: transparent;
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
// disabled / checked / after
|
||||
&:disabled:checked~.custom-control-label::after {
|
||||
background: 50%/50% 50% no-repeat;
|
||||
@include custom-radio-checked-icon($gray-300);
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background-size: 12px 12px;
|
||||
}
|
||||
|
||||
// disabled / not checked / before
|
||||
&:disabled:not(:checked)~.custom-control-label::before {
|
||||
border-color: $gray-300;
|
||||
background-color: transparent;
|
||||
background-color: $gray-600;
|
||||
border: 2px solid $gray-200;
|
||||
}
|
||||
|
||||
&:focus:disabled~.custom-control-label::before, &:active:disabled~.custom-control-label::before {
|
||||
box-shadow: 0 0 0 6px rgba($bg-disabled-control, 0.1);
|
||||
border-color: $gray-300;
|
||||
// focus and disabled / not checked / before
|
||||
&:focus:disabled~.custom-control-label::before,
|
||||
&:active:disabled~.custom-control-label::before {
|
||||
background-color: rgba($bg-disabled-control, 0.1);
|
||||
box-shadow: 0 0 0 6px rgba($bg-disabled-control, 0.1);
|
||||
border: 2px solid $gray-200;
|
||||
}
|
||||
|
||||
&:focus:disabled:checked~.custom-control-label::before, &:active:disabled:checked~.custom-control-label::before {
|
||||
border-color: $gray-400;
|
||||
// focus and disabled / checked / before
|
||||
&:focus:disabled:checked~.custom-control-label::before,
|
||||
&:active:disabled:checked~.custom-control-label::before {
|
||||
background: 50%/50% 50% no-repeat;
|
||||
@include custom-radio-checked-icon($gray-300);
|
||||
border: 2px solid $gray-200;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
27
website/client/src/assets/svg/big-gift.svg
Normal file
27
website/client/src/assets/svg/big-gift.svg
Normal file
@@ -0,0 +1,27 @@
|
||||
<svg width="176" height="67" viewBox="0 0 176 67" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path fill="#77F4C7" d="M35.667 11.667 40 9.5l-4.333-2.167L33.5 3l-2.167 4.333L27 9.5l4.333 2.167L33.5 16z"/>
|
||||
<path fill="#BDA8FF" d="M24.667 38.667 30 36l-5.333-2.667L22 28l-2.667 5.333L14 36l5.333 2.667L22 44z"/>
|
||||
<path fill="#8EEDF6" d="M35.667 63.667 39 62l-3.333-1.667L34 57l-1.667 3.333L29 62l3.333 1.667L34 67z"/>
|
||||
<path fill="#FFBE5D" d="M6.667 49.667 10 48l-3.333-1.667L5 43l-1.667 3.333L0 48l3.333 1.667L5 53z"/>
|
||||
<path fill="#FFB6B8" d="M5.667 20.667 8 19.5l-2.333-1.167L4.5 16l-1.167 2.333L1 19.5l2.333 1.167L4.5 23z"/>
|
||||
<g>
|
||||
<path fill="#77F4C7" d="M140.333 11.667 136 9.5l4.333-2.167L142.5 3l2.167 4.333L149 9.5l-4.333 2.167L142.5 16z"/>
|
||||
<path fill="#BDA8FF" d="M151.333 38.667 146 36l5.333-2.667L154 28l2.667 5.333L162 36l-5.333 2.667L154 44z"/>
|
||||
<path fill="#8EEDF6" d="M140.333 63.667 137 62l3.333-1.667L142 57l1.667 3.333L147 62l-3.333 1.667L142 67z"/>
|
||||
<path fill="#FFBE5D" d="M169.333 49.667 166 48l3.333-1.667L171 43l1.667 3.333L176 48l-3.333 1.667L171 53z"/>
|
||||
<path fill="#FFB6B8" d="M170.333 20.667 168 19.5l2.333-1.167L171.5 16l1.167 2.333L175 19.5l-2.333 1.167L171.5 23z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path d="M81.117 13.904c-2.139-4.838-6.274-9.113-11.25-9.324-4.976-.211-7.828 3.779-6.367 7.309 1.461 3.53 4.94 4.177 16.227 7.202 3.204.858 3.528-.35 1.39-5.187z" stroke="#22AEB7" stroke-width="4"/>
|
||||
<path d="M93.833 13.904c2.138-4.838 6.273-9.113 11.25-9.324 4.975-.211 7.828 3.779 6.367 7.309-1.462 3.53-4.94 4.177-16.227 7.202-3.205.858-3.528-.35-1.39-5.187z" stroke="#38C9C6" stroke-width="4"/>
|
||||
<path d="M87.128 11c-9.738 0-3.907 11.145 0 11.145 3.908 0 9.74-11.145 0-11.145z" fill="#46DDDA"/>
|
||||
<path fill="#6133B4" d="M62 33h52v34H62zM56 21h64v12H56z"/>
|
||||
<path fill-opacity=".5" fill="#FFF" style="mix-blend-mode:soft-light" d="M32 30h26v34H32z" transform="translate(56 3)"/>
|
||||
<path fill="#8EEDF6" d="M88 33h6v34h-6z"/>
|
||||
<path fill="#3BCAD7" d="M82 33h6v34h-6zM76 21h12v12H76z"/>
|
||||
<path fill="#8EEDF6" d="M88 21h12v12H88z"/>
|
||||
<path fill-opacity=".2" fill="#000" style="mix-blend-mode:multiply" d="M6 30h26v6H6zM20 18h12v6H20zM0 24h20v6H0zM44 24h20v6H44zM32 18h12v6H32zM6 58h26v6H6zM32 30h26v6H32zM32 58h26v6H32z" transform="translate(56 3)"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
@@ -1,5 +1,11 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
|
||||
<g fill="none" fill-rule="evenodd" stroke="#A5A1AC" stroke-width="2">
|
||||
<path d="M1 11L11 1M11 11L1 1"/>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>Icon/Close</title>
|
||||
<g id="Modals" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="Shop-Modals" transform="translate(-183.000000, -655.000000)" fill="#878190" fill-rule="nonzero">
|
||||
<g id="Icon/Close" transform="translate(183.000000, 655.000000)">
|
||||
<polygon id="Mask" points="12.1973467 2 14 3.80265326 9.80187117 8 14 12.1973467 12.1973467 14 8 9.80187117 3.80265326 14 2 12.1973467 6.19812883 8 2 3.80265326 3.80265326 2 8 6.19812883"></polygon>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 215 B After Width: | Height: | Size: 747 B |
@@ -122,6 +122,11 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.custom-control-input {
|
||||
z-index: -1;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.box:hover {
|
||||
cursor: pointer;
|
||||
opacity: 0.7;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<creator-intro />
|
||||
<profileModal />
|
||||
<report-flag-modal />
|
||||
<send-gems-modal />
|
||||
<send-gift-modal />
|
||||
<select-user-modal />
|
||||
<b-navbar
|
||||
id="habitica-menu"
|
||||
@@ -747,7 +747,7 @@ import creatorIntro from '../creatorIntro';
|
||||
import notificationMenu from './notificationsDropdown';
|
||||
import profileModal from '../userMenu/profileModal';
|
||||
import reportFlagModal from '../chat/reportFlagModal';
|
||||
import sendGemsModal from '@/components/payments/sendGemsModal';
|
||||
import sendGiftModal from '@/components/payments/sendGiftModal';
|
||||
import selectUserModal from '@/components/payments/selectUserModal';
|
||||
import sync from '@/mixins/sync';
|
||||
import userDropdown from './userDropdown';
|
||||
@@ -759,7 +759,7 @@ export default {
|
||||
notificationMenu,
|
||||
profileModal,
|
||||
reportFlagModal,
|
||||
sendGemsModal,
|
||||
sendGiftModal,
|
||||
selectUserModal,
|
||||
userDropdown,
|
||||
},
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
:class="{ condensed, expanded, 'd-flex': isHeader, row: !isHeader, }"
|
||||
@click="showMemberModal(member)"
|
||||
>
|
||||
<div :class="{ 'col-4': !isHeader }">
|
||||
<div class="avatar-container" :class="{ 'col-4': !isHeader }">
|
||||
<avatar
|
||||
:member="member"
|
||||
:hide-class-badge="classBadgePosition !== 'under-avatar'"
|
||||
@@ -92,6 +92,10 @@
|
||||
.member-details {
|
||||
white-space: nowrap;
|
||||
transition: all 0.15s ease-out;
|
||||
|
||||
.avatar-container {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.member-stats {
|
||||
|
||||
@@ -198,7 +198,7 @@ export default {
|
||||
appState.newGroup = false;
|
||||
appState.group = pick(this.amazonPayments.group, ['_id', 'memberCount', 'name']);
|
||||
}
|
||||
} else if (paymentType.indexOf('gift-') === 0) {
|
||||
} else if (paymentType && paymentType.indexOf('gift-') === 0) {
|
||||
appState.gift = this.amazonPayments.gift;
|
||||
appState.giftReceiver = this.amazonPayments.giftReceiver;
|
||||
} else if (paymentType === 'gems') {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<template>
|
||||
<div class="payments-column mx-auto mt-auto">
|
||||
<h4>{{ $t('choosePaymentMethod') }}</h4>
|
||||
<button
|
||||
v-if="stripeAvailable"
|
||||
class="btn btn-primary payment-button payment-item with-icon"
|
||||
@@ -80,6 +81,13 @@
|
||||
cursor: default !important;
|
||||
}
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 0.875rem;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -14,15 +14,44 @@
|
||||
</div>
|
||||
<h2
|
||||
v-else
|
||||
class="ml-2"
|
||||
class="d-flex flex-column mx-auto align-items-center"
|
||||
>
|
||||
{{ $t('sendGift') }}
|
||||
{{ $t('sendAGift') }}
|
||||
</h2>
|
||||
<div
|
||||
v-if="currentEvent && currentEvent.promo === 'g1g1'"
|
||||
class="g1g1-margin d-flex flex-column align-items-center"
|
||||
>
|
||||
<div
|
||||
class="svg-big-gift"
|
||||
v-once
|
||||
v-html="icons.bigGift"
|
||||
></div>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="d-flex flex-column align-items-center">
|
||||
<div
|
||||
class="svg-big-gift"
|
||||
v-once
|
||||
v-html="icons.bigGift"
|
||||
></div>
|
||||
</div>
|
||||
<div class="d-flex flex-column align-items-center">
|
||||
<div
|
||||
class="modal-close"
|
||||
v-if="currentEvent && currentEvent.promo === 'g1g1'"
|
||||
class="g1g1-modal-close"
|
||||
@click="close()"
|
||||
>
|
||||
<div
|
||||
class="g1g1-svg-icon"
|
||||
v-html="icons.close"
|
||||
></div>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="modal-close"
|
||||
@click="close()">
|
||||
<div
|
||||
class="svg-icon"
|
||||
v-html="icons.close"
|
||||
@@ -42,6 +71,7 @@
|
||||
v-model="userSearchTerm"
|
||||
class="form-control"
|
||||
type="text"
|
||||
ref="textBox"
|
||||
:placeholder="$t('usernameOrUserId')"
|
||||
:class="{
|
||||
'input-valid': foundUser._id,
|
||||
@@ -70,15 +100,20 @@
|
||||
<div
|
||||
v-else
|
||||
>
|
||||
{{ $t('selectGift') }}
|
||||
{{ $t('next') }}
|
||||
</div>
|
||||
</button>
|
||||
<a
|
||||
class="cancel-link mx-auto mt-3"
|
||||
@click="close()"
|
||||
<div
|
||||
v-if="currentEvent && currentEvent.promo ==='g1g1'"
|
||||
class="g1g1-cancel d-flex justify-content-center"
|
||||
v-html="$t('cancel')"
|
||||
@click="close()"
|
||||
>
|
||||
{{ $t('cancel') }}
|
||||
</a>
|
||||
{{ $t('cancel') }}
|
||||
</div>
|
||||
<div
|
||||
v-else>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -110,13 +145,16 @@
|
||||
@import '~@/assets/scss/mixins.scss';
|
||||
|
||||
#select-user-modal {
|
||||
.modal-content {
|
||||
width:448px;
|
||||
}
|
||||
|
||||
.input-group {
|
||||
margin-top: 0rem;
|
||||
}
|
||||
|
||||
.modal-dialog {
|
||||
width: 29.5rem;
|
||||
margin-top: 25vh;
|
||||
width: 448px;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
@@ -126,7 +164,16 @@
|
||||
margin: 0rem 0.25rem 0.25rem 0.25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
body.modal-open .modal {
|
||||
display: flex !important;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body.modal-open .modal .modal-dialog {
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -146,12 +193,12 @@
|
||||
|
||||
.g1g1 {
|
||||
background-image: url('~@/assets/images/g1g1-send.png');
|
||||
background-size: 472px 152px;
|
||||
width: 470px;
|
||||
background-size: 446px 152px;
|
||||
width: 446px;
|
||||
height: 152px;
|
||||
margin: -1rem 0rem 0rem -1rem;
|
||||
border-radius: 0.3rem 0.3rem 0rem 0rem;
|
||||
padding: 1.5rem;
|
||||
margin: -16px 0px 0px -16px;
|
||||
border-radius: 4.8px 4.8px 0px 0px;
|
||||
padding: 24px;
|
||||
color: $white;
|
||||
|
||||
h1 {
|
||||
@@ -169,6 +216,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
.g1g1-margin {
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
.g1g1-cancel {
|
||||
margin-top: 16px;
|
||||
color: $blue-10;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.g1g1-fine-print {
|
||||
color: $gray-100;
|
||||
background-color: $gray-700;
|
||||
@@ -176,6 +233,29 @@
|
||||
line-height: 1.33;
|
||||
}
|
||||
|
||||
.g1g1-modal-close {
|
||||
position: absolute;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
padding: 4px;
|
||||
right: 16px;
|
||||
top: 16px;
|
||||
cursor: pointer;
|
||||
|
||||
.g1g1-svg-icon {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
|
||||
& ::v-deep svg path {
|
||||
fill: #FFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.g1g1-modal-dialog {
|
||||
margin-top: 10vh;
|
||||
}
|
||||
|
||||
.input-error {
|
||||
color: $red-50;
|
||||
font-size: 90%;
|
||||
@@ -192,6 +272,18 @@
|
||||
border-color: $purple-500;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 1.25rem;
|
||||
line-height: 1.75rem;
|
||||
color: $purple-300;
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.svg-big-gift {
|
||||
width: 176px;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
.modal-close {
|
||||
position: absolute;
|
||||
width: 18px;
|
||||
@@ -206,14 +298,17 @@
|
||||
height: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
// import { nextTick } from 'vue'; // may not need this? I don't know!
|
||||
import debounce from 'lodash/debounce';
|
||||
import find from 'lodash/find';
|
||||
import isUUID from 'validator/lib/isUUID';
|
||||
import { mapState } from '@/libs/store';
|
||||
import closeIcon from '@/assets/svg/close.svg';
|
||||
import bigGiftIcon from '@/assets/svg/big-gift.svg';
|
||||
|
||||
export default {
|
||||
data () {
|
||||
@@ -223,6 +318,7 @@ export default {
|
||||
foundUser: {},
|
||||
icons: Object.freeze({
|
||||
close: closeIcon,
|
||||
bigGift: bigGiftIcon,
|
||||
}),
|
||||
};
|
||||
},
|
||||
@@ -281,7 +377,7 @@ export default {
|
||||
this.foundUser = result;
|
||||
}, 500),
|
||||
selectUser () {
|
||||
this.$root.$emit('habitica::send-gems', this.foundUser);
|
||||
this.$root.$emit('habitica::send-gift', this.foundUser);
|
||||
this.close();
|
||||
},
|
||||
onHide () {
|
||||
|
||||
659
website/client/src/components/payments/sendGiftModal.vue
Normal file
659
website/client/src/components/payments/sendGiftModal.vue
Normal file
@@ -0,0 +1,659 @@
|
||||
<template>
|
||||
<b-modal
|
||||
id="send-gift"
|
||||
:hide-footer="true"
|
||||
:hide-header="true"
|
||||
size="md"
|
||||
@hide="onHide()"
|
||||
>
|
||||
<div>
|
||||
<!-- header -->
|
||||
<div
|
||||
class="modal-close"
|
||||
@click="close()"
|
||||
>
|
||||
<div
|
||||
class="icon-close"
|
||||
v-html="icons.closeIcon"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h2 class="d-flex flex-column mx-auto align-items-center">
|
||||
{{ $t('sendAGift') }}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<!-- user avatar -->
|
||||
<div
|
||||
v-if="userReceivingGift"
|
||||
class="modal-body"
|
||||
>
|
||||
<avatar
|
||||
:member="userReceivingGift"
|
||||
:hideClassBadge="true"
|
||||
class="d-flex flex-column mx-auto align-items-center"
|
||||
/>
|
||||
<div class="avatar-spacer"></div>
|
||||
<div class="d-flex flex-column mx-auto align-items-center display-name">
|
||||
<!-- user display name and username -->
|
||||
<user-link
|
||||
:user-id="displayName"
|
||||
:name="displayName"
|
||||
:backer="userBacker"
|
||||
:contributor="userContributor"
|
||||
:class="display-name"
|
||||
/>
|
||||
</div>
|
||||
<div class="d-flex flex-column mx-auto align-items-center user-name">
|
||||
@{{ userName }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- menu area -->
|
||||
<div class="row">
|
||||
<div class="col-md-8 offset-md-2 text-center nav">
|
||||
<div
|
||||
class="nav-link"
|
||||
:class="{active: selectedPage === 'subscription'}"
|
||||
@click="selectPage('subscription')"
|
||||
>
|
||||
{{ $t('subscription') }}
|
||||
</div>
|
||||
<div
|
||||
class="nav-link"
|
||||
:class="{active: selectedPage !== 'subscription'}"
|
||||
@click="selectPage('buyGems')"
|
||||
>
|
||||
{{ $t('gems') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- subscriber block -->
|
||||
<subscription-options
|
||||
v-show="selectedPage === 'subscription'"
|
||||
class="subscribe-option"
|
||||
:userReceivingGift="userReceivingGift"
|
||||
/>
|
||||
|
||||
<!-- gem block -->
|
||||
<div
|
||||
v-show="selectedPage === 'buyGems'"
|
||||
>
|
||||
<div class="gem-group">
|
||||
<!-- buy gems with money -->
|
||||
<label v-once>
|
||||
{{ $t('howManyGemsPurchase') }}
|
||||
</label>
|
||||
<div class="d-flex flex-row align-items-center justify-content-center">
|
||||
<div
|
||||
class="gray-circle"
|
||||
@click="gift.gems.amount <= 0
|
||||
? gift.gems.amount = 0
|
||||
: gift.gems.amount--"
|
||||
>
|
||||
<div
|
||||
class="icon-negative"
|
||||
v-html="icons.negativeIcon"
|
||||
></div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend input-group-icon align-items-center">
|
||||
<div
|
||||
class="icon-gem"
|
||||
v-html="icons.gemIcon"
|
||||
></div>
|
||||
</div>
|
||||
<input
|
||||
id="gemsForm"
|
||||
v-model.number="gift.gems.amount"
|
||||
class="form-control"
|
||||
max="9999"
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="gray-circle"
|
||||
@click="gift.gems.amount++"
|
||||
>
|
||||
<div
|
||||
class="icon-positive"
|
||||
v-html="icons.positiveIcon"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- the word "total" -->
|
||||
<div class="buy-gem-total">
|
||||
{{ $t('sendGiftTotal') }}
|
||||
</div>
|
||||
|
||||
<!-- the actual dollar amount -->
|
||||
<div class="buy-gem-amount">
|
||||
<span>
|
||||
{{ formatter.format(totalGems) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- change to sending own gems page -->
|
||||
<div
|
||||
:class="{active: selectedPage === 'ownGems'}"
|
||||
class="gem-state-change"
|
||||
@click="selectPage('ownGems')"
|
||||
>
|
||||
{{ $t('wantToSendOwnGems') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- paying for gems -->
|
||||
<payments-buttons
|
||||
class="payment-buttons"
|
||||
:stripe-fn="() => redirectToStripe({gift, uuid: userReceivingGift._id, receiverName})"
|
||||
:paypal-fn="() => openPaypalGift({
|
||||
gift: gift, giftedTo: userReceivingGift._id, receiverName,
|
||||
})"
|
||||
:amazon-data="{type: 'single', gift, giftedTo: userReceivingGift._id, receiverName}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- send gems from balance -->
|
||||
<div
|
||||
v-show="selectedPage === 'ownGems'"
|
||||
>
|
||||
<div class="gem-group">
|
||||
<label v-once>
|
||||
{{ $t('howManyGemsSend') }}
|
||||
</label>
|
||||
<div class="d-flex align-items-center justify-content-center">
|
||||
<div
|
||||
class="gray-circle"
|
||||
@click="gift.gems.amount <= 0
|
||||
? gift.gems.amount = 0
|
||||
: gift.gems.amount--"
|
||||
>
|
||||
<div
|
||||
class="icon-negative"
|
||||
v-html="icons.negativeIcon"
|
||||
></div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend input-group-icon align-items-center">
|
||||
<div
|
||||
class="icon-gem"
|
||||
v-html="icons.gemIcon"
|
||||
></div>
|
||||
</div>
|
||||
<input
|
||||
id="gemsForm"
|
||||
v-model="gift.gems.amount"
|
||||
class="form-control"
|
||||
:max="maxGems"
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="gray-circle"
|
||||
@click="gift.gems.amount < maxGems
|
||||
? gift.gems.amount++
|
||||
: gift.gems.amount = maxGems"
|
||||
>
|
||||
<div
|
||||
class="icon-positive"
|
||||
v-html="icons.positiveIcon"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="align-items-middle">
|
||||
<div class="d-flex justify-content-center align-items-middle">
|
||||
<span class="balance-text">
|
||||
{{ $t('yourBalance') }}
|
||||
</span>
|
||||
<span
|
||||
class="icon-gem balance-gem-margin"
|
||||
style="display: inline-block;"
|
||||
v-html="icons.gemIcon"
|
||||
></span>
|
||||
<span
|
||||
class="balance-gems"
|
||||
>
|
||||
{{ maxGems }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex flex-column justify-content-center align-items-middle mt-3">
|
||||
<button
|
||||
v-if="fromBal"
|
||||
class="btn btn-primary mx-auto mt-2"
|
||||
type="submit"
|
||||
:disabled="sendingInProgress"
|
||||
@click="sendGift()"
|
||||
>
|
||||
{{ $t("send") }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- change to buying gems page -->
|
||||
<div
|
||||
:class="{active: selectedPage === 'buyGems'}"
|
||||
class="gem-state-change"
|
||||
@click="selectPage('buyGems')"
|
||||
>
|
||||
{{ $t('needToPurchaseGems') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</b-modal>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@import '~@/assets/scss/mixins.scss';
|
||||
#send-gift {
|
||||
.modal-dialog {
|
||||
max-width: 448px;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
width: 448px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 14px 28px 0 rgba(26, 24, 29, 0.24), 0 10px 10px 0 rgba(26, 24, 29, 0.28);
|
||||
}
|
||||
.modal-body{
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.modal-close {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 16px;
|
||||
cursor: pointer;
|
||||
|
||||
.icon-close {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
vertical-align: middle;
|
||||
|
||||
& ::v-deep svg path {
|
||||
fill: #878190;
|
||||
}
|
||||
& :hover {
|
||||
fill: #686274;
|
||||
}
|
||||
}
|
||||
}
|
||||
#subscription-form .subscribe-option {
|
||||
background: #F9F9F9;
|
||||
}
|
||||
|
||||
#subscription-form .selected {
|
||||
background: rgba(213, 200, 255, 0.32);
|
||||
// using rgba for transparency
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style scoped lang="scss">
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
h2 {
|
||||
color: $purple-300;
|
||||
padding-top: 2rem;
|
||||
}
|
||||
|
||||
.avatar-spacer {
|
||||
height: 9px;
|
||||
}
|
||||
|
||||
.display-name {
|
||||
font-size: 0.875rem;
|
||||
font-weight: bold;
|
||||
line-height: 1.71;
|
||||
margin: 0px 6px 0 20px;
|
||||
}
|
||||
|
||||
.display-name a:hover{
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.user-name {
|
||||
font-size: 0.75rem;
|
||||
line-height: 1.33;
|
||||
text-align: center;
|
||||
color: $gray-100;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.row {
|
||||
background-color: $gray-700;
|
||||
margin: 0 0 0 0;
|
||||
min-height: 32px;
|
||||
}
|
||||
|
||||
.nav {
|
||||
font-weight: bold;
|
||||
font-size: 0.75rem;
|
||||
min-height: 32px;
|
||||
padding: 16px 0 0 0;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
color: $gray-100;
|
||||
display: inline-block;
|
||||
padding: 0px 8px 6px 8px;
|
||||
|
||||
&.active {
|
||||
color: $purple-300;
|
||||
border-bottom: 2px solid $purple-400;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: $purple-300;
|
||||
border-bottom: 2px solid $purple-400;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.gem-group {
|
||||
padding: 0 0 24px 0;
|
||||
background-color: $gray-700;
|
||||
margin: 0 0 0 0;
|
||||
border-bottom-right-radius: 8px;
|
||||
border-bottom-left-radius: 8px
|
||||
}
|
||||
|
||||
label {
|
||||
color: $gray-50;
|
||||
font-size: 0.875rem;
|
||||
font-weight: bold;
|
||||
line-height: 1.71;
|
||||
margin: 12px 0 16px 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.input-group {
|
||||
width: 94px;
|
||||
height: 32px;
|
||||
margin: 0px 16px 0px 16px;
|
||||
padding: 0;
|
||||
border-radius: 2px;
|
||||
border: solid 1px $gray-400;
|
||||
background-color: $white;
|
||||
}
|
||||
|
||||
.gray-circle {
|
||||
border-radius: 100%;
|
||||
border: solid 2px $gray-300;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
border-color: $purple-400;
|
||||
}
|
||||
}
|
||||
|
||||
.gray-circle:hover{
|
||||
.icon-positive, .icon-negative {
|
||||
& ::v-deep svg path {
|
||||
fill: $purple-400;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.icon-gem {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.icon-positive, .icon-negative {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin: 4px auto;
|
||||
|
||||
& ::v-deep svg path {
|
||||
fill: $gray-300;
|
||||
}
|
||||
}
|
||||
|
||||
.buy-gem-total {
|
||||
font-size: 0.875rem;
|
||||
font-weight: bold;
|
||||
line-height: 1.71;
|
||||
padding-top: 24px;
|
||||
text-align: center;
|
||||
height: 28px;
|
||||
}
|
||||
|
||||
.buy-gem-amount {
|
||||
font-size: 1.25rem;
|
||||
font-weight: bold;
|
||||
line-height: 1.4;
|
||||
margin: 16px 0 24px 0;
|
||||
text-align: center;
|
||||
height: 28px;
|
||||
color: $green-10;
|
||||
}
|
||||
|
||||
.balance-text {
|
||||
font-size: 0.75rem;
|
||||
font-weight: bold;
|
||||
color: $gray-100;
|
||||
line-height: 1.33;
|
||||
margin: 12px 0px 0px 70px;
|
||||
}
|
||||
|
||||
.balance-gem-margin {
|
||||
margin: 8px 4px 0px 8px;
|
||||
}
|
||||
|
||||
.balance-gems {
|
||||
font-size: 0.75rem;
|
||||
color: $gray-100;
|
||||
line-height: 1.33;
|
||||
margin: 12px 71px 0px 4px;
|
||||
}
|
||||
|
||||
.gem-state-change {
|
||||
color: $blue-10;
|
||||
font-size: 0.875rem;
|
||||
min-height: 24px;
|
||||
margin: 16px 0 0;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.subscribe-option {
|
||||
border-bottom-left-radius: 8px;
|
||||
border-bottom-right-radius: 8px;
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
.payment-buttons {
|
||||
padding: 24px 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
// libs imports
|
||||
import { mapState } from '@/libs/store';
|
||||
|
||||
// mixins imports
|
||||
import paymentsMixin from '../../mixins/payments';
|
||||
|
||||
// component imports
|
||||
import avatar from '../avatar';
|
||||
import userLink from '../userLink';
|
||||
import subscriptionOptions from '../settings/subscriptionOptions.vue';
|
||||
import paymentsButtons from '@/components/payments/buttons/list';
|
||||
|
||||
// svg imports
|
||||
import closeIcon from '@/assets/svg/close.svg';
|
||||
import gemIcon from '@/assets/svg/gem.svg';
|
||||
import positiveIcon from '@/assets/svg/positive.svg';
|
||||
import negativeIcon from '@/assets/svg/negative.svg';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
avatar,
|
||||
subscriptionOptions,
|
||||
paymentsButtons,
|
||||
userLink,
|
||||
},
|
||||
mixins: [
|
||||
paymentsMixin,
|
||||
],
|
||||
data () {
|
||||
return {
|
||||
subscription: {
|
||||
key: '',
|
||||
},
|
||||
icons: Object.freeze({
|
||||
closeIcon,
|
||||
gemIcon,
|
||||
positiveIcon,
|
||||
negativeIcon,
|
||||
}),
|
||||
userReceivingGift: {
|
||||
profile: '',
|
||||
},
|
||||
name: '',
|
||||
display: '',
|
||||
selectedPage: 'subscription',
|
||||
gift: {
|
||||
type: 'gems',
|
||||
gems: {
|
||||
amount: 0,
|
||||
fromBalance: true,
|
||||
},
|
||||
},
|
||||
sendingInProgress: false,
|
||||
amazonPayments: {},
|
||||
gemCost: 1,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
userLoggedIn: 'user.data',
|
||||
}),
|
||||
userName () {
|
||||
const userName = this.userReceivingGift.auth
|
||||
&& this.userReceivingGift.auth.local
|
||||
&& this.userReceivingGift.auth.local.username;
|
||||
return userName;
|
||||
},
|
||||
displayName () {
|
||||
const displayName = this.userReceivingGift.profile.name;
|
||||
return displayName;
|
||||
},
|
||||
userBacker () {
|
||||
const userBacker = this.userReceivingGift.backer;
|
||||
return userBacker;
|
||||
},
|
||||
userContributor () {
|
||||
const userContributor = this.userReceivingGift.contributor;
|
||||
return userContributor;
|
||||
},
|
||||
tierIcon () {
|
||||
if (this.isNPC) {
|
||||
return this.icons.tierNPC;
|
||||
}
|
||||
return this.icons[`tier${this.level}`];
|
||||
},
|
||||
fromBal () {
|
||||
return this.gift.type === 'gems' && this.gift.gems.fromBalance;
|
||||
},
|
||||
maxGems () {
|
||||
const maxGems = this.fromBal ? this.userLoggedIn.balance * 4 : 9999;
|
||||
return maxGems;
|
||||
},
|
||||
formatter () {
|
||||
const formatter = new Intl.NumberFormat('en-US', {
|
||||
style: 'currency',
|
||||
currency: 'USD',
|
||||
minimumFractionDigits: 2,
|
||||
});
|
||||
return formatter;
|
||||
},
|
||||
totalGems () {
|
||||
const totalGems = this.gift.gems.amount * 0.25;
|
||||
return totalGems;
|
||||
},
|
||||
receiverName () {
|
||||
if (
|
||||
this.userReceivingGift.auth
|
||||
&& this.userReceivingGift.auth.local
|
||||
&& this.userReceivingGift.auth.local.username
|
||||
) {
|
||||
return this.userReceivingGift.auth.local.username;
|
||||
}
|
||||
return this.userReceivingGift.profile.name;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
startingPage () {
|
||||
this.selectedPage = this.startingPage;
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.$root.$on('habitica::send-gift', data => {
|
||||
this.userReceivingGift = data;
|
||||
if (this.$store.state.giftModalOptions.startingPage) {
|
||||
this.selectedPage = this.$store.state.giftModalOptions.startingPage;
|
||||
this.$store.state.giftModalOptions.startingPage = '';
|
||||
this.selectPage(this.selectedPage);
|
||||
} else {
|
||||
this.selectPage(this.startingPage);
|
||||
}
|
||||
this.setGemDefaults();
|
||||
this.$root.$emit('bv::show::modal', 'send-gift');
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
close () {
|
||||
this.$root.$emit('bv::hide::modal', 'send-gift');
|
||||
},
|
||||
setGemDefaults () {
|
||||
if (this.selectedPage === 'buyGems') {
|
||||
this.gift.gems.amount = 20;
|
||||
} else if (this.selectedPage === 'ownGems') {
|
||||
this.gift.gems.amount = 1;
|
||||
} else {
|
||||
this.gift.gems.amount = 0;
|
||||
}
|
||||
},
|
||||
selectPage (page) {
|
||||
if (page === this.selectedPage) return;
|
||||
if (page === 'buyGems') this.selectedPage = 'buyGems';
|
||||
if (page === 'buyGems' && this.selectedPage === 'ownGems') return;
|
||||
this.selectedPage = page || 'subscription';
|
||||
this.setGemDefaults();
|
||||
},
|
||||
async sendGift () {
|
||||
this.sendingInProgress = true;
|
||||
await this.$store.dispatch('members:transferGems', {
|
||||
toUserId: this.userReceivingGift._id,
|
||||
gemAmount: this.gift.gems.amount,
|
||||
});
|
||||
this.close();
|
||||
setTimeout(() => { // wait for the send gem modal to be closed
|
||||
this.$root.$emit('habitica:payment-success', {
|
||||
paymentMethod: 'balance',
|
||||
paymentCompleted: true,
|
||||
paymentType: 'gift-gems-balance',
|
||||
gift: {
|
||||
gems: {
|
||||
amount: this.gift.gems.amount,
|
||||
},
|
||||
},
|
||||
giftReceiver: this.receiverName,
|
||||
});
|
||||
}, 500);
|
||||
},
|
||||
onHide () {
|
||||
this.sendingInProgress = false;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -739,6 +739,14 @@ export default {
|
||||
} else if (attribute === 'email') {
|
||||
this.user.auth.local.email = updates.newEmail;
|
||||
window.alert(this.$t('emailSuccess')); // eslint-disable-line no-alert
|
||||
} else if (attribute === 'password') {
|
||||
this.passwordUpdates = {};
|
||||
this.$store.dispatch('snackbars:add', {
|
||||
title: 'Habitica',
|
||||
text: this.$t('passwordSuccess'),
|
||||
type: 'success',
|
||||
timeout: true,
|
||||
});
|
||||
}
|
||||
},
|
||||
async changeDisplayName (newName) {
|
||||
|
||||
@@ -450,10 +450,6 @@
|
||||
background-color: $white;
|
||||
}
|
||||
|
||||
.subscribe-option {
|
||||
border-bottom: 1px solid $gray-600;
|
||||
}
|
||||
|
||||
.svg-amazon-pay {
|
||||
width: 208px;
|
||||
}
|
||||
|
||||
@@ -10,10 +10,17 @@
|
||||
:value="block.key"
|
||||
class="subscribe-option pt-2 pl-5 pb-3 mb-0"
|
||||
:class="{selected: subscription.key === block.key}"
|
||||
@click.native="subscription.key = block.key"
|
||||
@click.native="updateSubscriptionData(block.key)"
|
||||
>
|
||||
<!-- eslint-enable vue/no-use-v-if-with-v-for -->
|
||||
<div
|
||||
v-if="userReceivingGift && userReceivingGift._id"
|
||||
class="subscription-text ml-2 mb-1"
|
||||
v-html="$t('giftSubscriptionRateText', {price: block.price, months: block.months})"
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="subscription-text ml-2 mb-1"
|
||||
v-html="$t('subscriptionRateText', {price: block.price, months: block.months})"
|
||||
>
|
||||
@@ -25,7 +32,18 @@
|
||||
</div>
|
||||
</b-form-radio>
|
||||
</b-form-group>
|
||||
<!-- payment buttons first is for gift subs and the second is for renewing subs -->
|
||||
<payments-buttons
|
||||
v-if="userReceivingGift && userReceivingGift._id"
|
||||
:disabled="!subscription.key"
|
||||
:stripe-fn="() => redirectToStripe({gift, uuid: userReceivingGift._id, receiverName})"
|
||||
:paypal-fn="() => openPaypalGift({
|
||||
gift: gift, giftedTo: userReceivingGift._id, receiverName,
|
||||
})"
|
||||
:amazon-data="{type: 'single', gift, giftedTo: userReceivingGift._id, receiverName}"
|
||||
/>
|
||||
<payments-buttons
|
||||
v-else
|
||||
:disabled="!subscription.key"
|
||||
:stripe-fn="() => redirectToStripe({
|
||||
subscription: subscription.key,
|
||||
@@ -43,6 +61,7 @@
|
||||
|
||||
<style lang="scss">
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
#subscription-form {
|
||||
.custom-control .custom-control-label::before,
|
||||
.custom-radio .custom-control-input:checked ~ .custom-control-label::after {
|
||||
@@ -101,11 +120,22 @@ export default {
|
||||
mixins: [
|
||||
paymentsMixin,
|
||||
],
|
||||
props: {
|
||||
userReceivingGift: {
|
||||
type: Object,
|
||||
default () {},
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
subscription: {
|
||||
key: null,
|
||||
key: 'basic_earned',
|
||||
},
|
||||
gift: {
|
||||
type: 'subscription',
|
||||
subscription: { key: 'basic_earned' },
|
||||
},
|
||||
receiverName: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -114,7 +144,6 @@ export default {
|
||||
},
|
||||
subscriptionBlocksOrdered () {
|
||||
const subscriptions = filter(subscriptionBlocks, o => o.discount !== true);
|
||||
|
||||
return sortBy(subscriptions, [o => o.months]);
|
||||
},
|
||||
},
|
||||
@@ -131,6 +160,10 @@ export default {
|
||||
return '<span class="subscription-bubble px-2 py-1">Gem cap at 25</span>';
|
||||
}
|
||||
},
|
||||
updateSubscriptionData (key) {
|
||||
this.subscription.key = key;
|
||||
if (this.userReceivingGift._id) this.gift.subscription.key = key;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -209,6 +209,7 @@
|
||||
<li>Fox_town</li>
|
||||
<li>MaybeSteveRogers</li>
|
||||
<li>shanaqui</li>
|
||||
<li>deilann (not yet pictured)</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -218,7 +219,7 @@
|
||||
{{ $t('commGuidePara014') }}<br>
|
||||
<em>
|
||||
Lemoness, lefnire, Slappybag, litenull, Shaner, Bobbyroberts99, wc8,
|
||||
deilann, Breadstrings, Megan, Blade, and Daniel the Bard
|
||||
Breadstrings, Megan, Blade, and Daniel the Bard
|
||||
</em>
|
||||
</p>
|
||||
<h2 id="final">
|
||||
|
||||
@@ -662,6 +662,11 @@
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.custom-control-input {
|
||||
z-index: -1;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
.form-group {
|
||||
margin-bottom: 1rem;
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-6 offset-md-3 text-center nav">
|
||||
<div class="text-center nav">
|
||||
<div
|
||||
class="nav-item"
|
||||
:class="{active: selectedPage === 'profile'}"
|
||||
@@ -470,6 +470,7 @@
|
||||
.gift-icon svg {
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -538,6 +539,7 @@
|
||||
}
|
||||
|
||||
.nav {
|
||||
width: 100%;
|
||||
font-weight: bold;
|
||||
min-height: 40px;
|
||||
justify-content: center;
|
||||
@@ -710,6 +712,27 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 990px) {
|
||||
.profile-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
.profile-actions :not(:last-child) {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.profile-actions {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 550px) {
|
||||
.member-details {
|
||||
flex-direction: column;
|
||||
}
|
||||
.member-details .avatar {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
@@ -969,7 +992,8 @@ export default {
|
||||
axios.post(`/api/v4/user/block/${this.user._id}`);
|
||||
},
|
||||
openSendGemsModal () {
|
||||
this.$root.$emit('habitica::send-gems', this.user);
|
||||
this.$store.state.giftModalOptions.startingPage = 'buyGems';
|
||||
this.$root.$emit('habitica::send-gift', this.user);
|
||||
},
|
||||
adminTurnOnShadowMuting () {
|
||||
if (!this.hero.flags) {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
class="standard-page"
|
||||
>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="stats-section-equipment col-12 col-md-6">
|
||||
<h2 class="text-center">
|
||||
{{ $t('equipment') }}
|
||||
</h2>
|
||||
@@ -12,7 +12,7 @@
|
||||
<div
|
||||
v-for="(label, key) in equipTypes"
|
||||
:key="key"
|
||||
class="col-12 col-md-4 item-wrapper"
|
||||
class="item-wrapper"
|
||||
>
|
||||
<div
|
||||
v-if="label !== 'skip'"
|
||||
@@ -48,7 +48,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="stats-section-costume col-12 col-md-6">
|
||||
<h2 class="text-center">
|
||||
{{ $t('costume') }}
|
||||
</h2>
|
||||
@@ -57,7 +57,7 @@
|
||||
<div
|
||||
v-for="(label, key) in equipTypes"
|
||||
:key="key"
|
||||
class="col-12 col-md-4 item-wrapper"
|
||||
class="item-wrapper"
|
||||
>
|
||||
<!-- Append a "C" to the key name since HTML IDs have to be unique.-->
|
||||
<div
|
||||
@@ -111,7 +111,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="row pet-mount-row">
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="stats-section-pets col-12 col-md-6">
|
||||
<h2
|
||||
v-once
|
||||
class="text-center"
|
||||
@@ -119,8 +119,7 @@
|
||||
{{ $t('pets') }}
|
||||
</h2>
|
||||
<div class="well pet-mount-well">
|
||||
<div class="row col-12">
|
||||
<div class="col-12 col-md-4">
|
||||
<div class="pet-mount-well-image">
|
||||
<div
|
||||
class="box"
|
||||
:class="{white: user.items.currentPet}"
|
||||
@@ -131,7 +130,7 @@
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-8">
|
||||
<div class="pet-mount-well-text">
|
||||
<div>{{ formatAnimal(user.items.currentPet, 'pet') }}</div>
|
||||
<div>
|
||||
<strong>{{ $t('petsFound') }}:</strong>
|
||||
@@ -142,10 +141,9 @@
|
||||
{{ beastMasterProgress(user.items.pets) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="stats-section-mounts col-12 col-md-6">
|
||||
<h2
|
||||
v-once
|
||||
class="text-center"
|
||||
@@ -153,28 +151,26 @@
|
||||
{{ $t('mounts') }}
|
||||
</h2>
|
||||
<div class="well pet-mount-well">
|
||||
<div class="row col-12">
|
||||
<div class="col-12 col-md-4">
|
||||
<div class="pet-mount-well-image">
|
||||
<div
|
||||
class="box"
|
||||
:class="{white: user.items.currentMount}"
|
||||
>
|
||||
<div
|
||||
class="box"
|
||||
:class="{white: user.items.currentMount}"
|
||||
>
|
||||
<div
|
||||
class="mount"
|
||||
:class="`Mount_Icon_${user.items.currentMount}`"
|
||||
></div>
|
||||
</div>
|
||||
class="mount"
|
||||
:class="`Mount_Icon_${user.items.currentMount}`"
|
||||
></div>
|
||||
</div>
|
||||
<div class="col-12 col-md-8">
|
||||
<div>{{ formatAnimal(user.items.currentMount, 'mount') }}</div>
|
||||
<div>
|
||||
<strong>{{ $t('mountsTamed') }}:</strong>
|
||||
<span>{{ totalCount(user.items.mounts) }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<strong>{{ $t('mountMasterProgress') }}:</strong>
|
||||
<span>{{ mountMasterProgress(user.items.mounts) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pet-mount-well-text">
|
||||
<div>{{ formatAnimal(user.items.currentMount, 'mount') }}</div>
|
||||
<div>
|
||||
<strong>{{ $t('mountsTamed') }}:</strong>
|
||||
<span>{{ totalCount(user.items.mounts) }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<strong>{{ $t('mountMasterProgress') }}:</strong>
|
||||
<span>{{ mountMasterProgress(user.items.mounts) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -309,15 +305,13 @@
|
||||
v-if="showStatsSave"
|
||||
class="row save-row"
|
||||
>
|
||||
<div class="col-12 col-md-6 offset-md-3 text-center">
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
:disabled="loading"
|
||||
@click="saveAttributes()"
|
||||
>
|
||||
{{ loading ? $t('loading') : $t('save') }}
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
:disabled="loading"
|
||||
@click="saveAttributes()"
|
||||
>
|
||||
{{ loading ? $t('loading') : $t('save') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -650,10 +644,17 @@ export default {
|
||||
border-radius: 2px;
|
||||
padding: 0.4em;
|
||||
padding-top: 1em;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.well.pet-mount-well {
|
||||
padding-left: 15px;
|
||||
padding-bottom: 1em;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: flex-start;
|
||||
|
||||
strong {
|
||||
margin-right: .2em;
|
||||
@@ -690,12 +691,13 @@ export default {
|
||||
}
|
||||
|
||||
.save-row {
|
||||
margin-top: 1em;
|
||||
margin: 2em 0 1em 0;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.gear.box {
|
||||
vertical-align: top;
|
||||
margin: 0 auto;
|
||||
// margin: 0 auto;
|
||||
}
|
||||
|
||||
.gear-label {
|
||||
@@ -721,4 +723,34 @@ export default {
|
||||
// breaks the long words without a space
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
@media (max-width: 850px) {
|
||||
#stats .col-md-6 {
|
||||
flex: none;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
@media(max-width: 990px) {
|
||||
.modal-body #stats .col-md-6 {
|
||||
flex: none;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
[class^="stats-section-"] {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
#allocation {
|
||||
.box {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.col-9 {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.col-9 div:first-child {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -39,6 +39,11 @@ export default [
|
||||
type: 'Moderator',
|
||||
uuid: '28771972-ca6d-4c03-8261-e1734aa7d21d',
|
||||
},
|
||||
{
|
||||
name: 'deilann',
|
||||
type: 'Moderator',
|
||||
uuid: 'e7b5d1e2-3b6e-4192-b867-8bafdb03eeec',
|
||||
},
|
||||
{
|
||||
name: 'Dewines',
|
||||
type: 'Moderator',
|
||||
|
||||
@@ -124,6 +124,9 @@ export default function () {
|
||||
profileOptions: {
|
||||
startingPage: '',
|
||||
},
|
||||
giftModalOptions: {
|
||||
startingPage: '',
|
||||
},
|
||||
rageModalOptions: {
|
||||
npc: '',
|
||||
},
|
||||
|
||||
1
website/common/locales/ceb/achievements.json
Normal file
1
website/common/locales/ceb/achievements.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
website/common/locales/ceb/challenge.json
Normal file
1
website/common/locales/ceb/challenge.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
website/common/locales/ceb/merch.json
Normal file
1
website/common/locales/ceb/merch.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
1
website/common/locales/ceb/noscript.json
Normal file
1
website/common/locales/ceb/noscript.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
3
website/common/locales/ceb/settings.json
Normal file
3
website/common/locales/ceb/settings.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
|
||||
}
|
||||
@@ -2476,7 +2476,7 @@
|
||||
"armorSpecialFall2021MageNotes": "Kragen mit vielen spitzen Spitzen sind besonders Beliebt bei Basisbösewichten. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2021 Herbstausrüstung.",
|
||||
"armorSpecialFall2021HealerText": "Roben des Erweckens",
|
||||
"armorSpecialFall2021HealerNotes": "Hergestellt aus flammen-resistentem Material sind diese Roben besonders geeignet um heilende Flammen und reinige Feuer anzuwenden. Erhöht Ausdauer um <%= con %>. Limitierte Ausgabe 2021 Herbstausrüstung.",
|
||||
"armorArmoireBagpipersKiltNotes": "Ein robuster, langlebiger Kilt wird Dir gute Dienste erweisen. Erhöht Ausdauer um <%= con %>. Dudelsackpfeiferset (Gegenstand 2 von 3).",
|
||||
"armorArmoireBagpipersKiltNotes": "Ein robuster, langlebiger Kilt wird Dir gute Dienste erweisen. Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Dudelsackpfeiferset (Gegenstand 2 von 3).",
|
||||
"armorArmoireHeraldsTunicText": "Tunika des Herolds",
|
||||
"armorArmoireSoftBlackSuitText": "Weicher Schwarzer Anzug",
|
||||
"headSpecialFall2021RogueNotes": "Tja, Du steckst fest. Jetzt bist Du dazu verdonnert alte Verliese heimzusuchen und allerlei Unrat mit dir aufzusammeln. Ohweh! Erhöht Wahrnehmung um <%= per %>. Limitierte Ausgabe 2021 Herbstausrüstung.",
|
||||
@@ -2489,7 +2489,7 @@
|
||||
"armorArmoireSoftBlackSuitNotes": "Schwarz ist eine mysteriöse Farbe. Mit Sicherheit inspiriert es zu den interessantesten Träumen. Erhöht Konstitution und Wahrnehmung um jeweils <%=attrs %>. Verzauberter Schrank: Schwarzes Wohlfühl-Set (Gegenstand 2 von 3).",
|
||||
"headSpecialFall2021HealerNotes": "Deine eigene Magie lässt deine Haare zu schockierenden, hellen Flammen werden, wenn du diese Maske aufsetzt. Erhöht Intelligenz um <%= int %>. Limitierte Ausgabe 2021 Herbstausrüstung.",
|
||||
"weaponArmoireSkullLanternText": "Totenkopflaterne",
|
||||
"weaponArmoireSkullLanternNotes": "Lasse ihr Leuchten deinen Weg durch die tiefste Finsternis erhellen. Erhöht Intelligenz um <%= int %>. Verzauberter Schrank:Unabhängiger Gegenstand.",
|
||||
"weaponArmoireSkullLanternNotes": "Lasse ihr Leuchten deinen Weg durch die tiefste Finsternis erhellen. Erhöht Intelligenz um <%= int %>. Verzauberter Schrank: Unabhängiger Gegenstand.",
|
||||
"offHandCapitalized": "Schildhand-Gegenstand",
|
||||
"armorMystery202112Text": "Antarktischer Nixenschwanz",
|
||||
"armorMystery202112Notes": "Gleite mit diesem schimmerden Schwanz durch eisige Gewässser ohne jegliche Kälte zu spühren. Gewährt keinen Attributbonus. Dezember 2021 Abonnentengegenstand.",
|
||||
@@ -2625,7 +2625,7 @@
|
||||
"weaponArmoireHuntingHornNotes": "Tuuut! Tuut! Tuut! Rufe deine Party für ein Abenteuer oder eine Quest zusammen, indem Du auf diesem Horn spielst. Erhöht Stärke um <%= str %> und Intelligenz um <%= int %>. Verzauberter Schrank: Musikinstrument Set 1 (Gegenstand 1 von 3)",
|
||||
"headArmoireStrawRainHatText": "Stroh-Regenhut",
|
||||
"shieldArmoireSnareDrumText": "Kleine Trommel",
|
||||
"shieldArmoireSnareDrumNotes": "Rat-a-tat-ta! Rufe Deine Party für eine Parade oder einen Marsch zusammen, indem Du auf dieser Trommel spielst. Erhöht Ausdauer um <%= con %> und Intelligenz um <%= int %>. Musikinstrument Set 1 (Gegenstand 3 von 3)",
|
||||
"shieldArmoireSnareDrumNotes": "Rat-a-tat-ta! Rufe Deine Party für eine Parade oder einen Marsch zusammen, indem Du auf dieser Trommel spielst. Erhöht Ausdauer um <%= con %> und Intelligenz um <%= int %>. Verzauberter Schrank: Musikinstrument Set 1 (Gegenstand 3 von 3)",
|
||||
"shieldArmoireSpanishGuitarNotes": "Kling! Kling! Klooong! Rufe Deine Party für ein Konzert oder eine Feierlichkeit zusammen, indem Du auf dieser Gitarre spielst. Erhöht Wahrnehmung um <%= per %> und Intelligenz um <%= int %>. Verzauberter Schrank: Musikinstrument Set 1 (Gegenstand 2 von 3)",
|
||||
"shieldArmoireSpanishGuitarText": "Spanische Gitarre",
|
||||
"armorArmoireStrawRaincoatNotes": "Dieser gewebte Strohumhang wird Dich während Deiner Quest trocken halten und Deine Rüstung vor dem Rosten bewahren. Wage Dich jedoch nicht zu nah an Kerzen heran. Erhöht Ausdauer um <%= con %>. Verzauberter Schrank: Stroh Regenmantel Set (Gegenstand 1 von 2).",
|
||||
@@ -2634,13 +2634,13 @@
|
||||
"backMystery202206Notes": "Wunderliche Flügel aus Wasser und Wellen! Verleiht keinen Vorteil. Juni 2022 Abonnentengegenstand.",
|
||||
"headMystery202206Notes": "Die blaue Perle in diesem Diadem verleiht dir Wasserbändigungskräfte. Nutze sie weise! Verleiht keinen Vorteil. Juni 2022 Abonnentengegenstand.",
|
||||
"weaponArmoireBlueKiteText": "Blauer Drachen",
|
||||
"weaponArmoireBlueKiteNotes": "Hoch am Himmel fliegt der Drachen, welche Stunts kann er wohl machen? Erhöht alle Werte um jeweils <%= attrs %> . Verzauberter Kleiderschrank: Drachen Set (Gegenstand 1 von 5)",
|
||||
"weaponArmoireBlueKiteNotes": "Hoch am Himmel fliegt der Drachen, welche Stunts kann er wohl machen? Erhöht alle Werte um jeweils <%= attrs %> . Verzauberter Schrank: Drachen Set (Gegenstand 1 von 5)",
|
||||
"weaponArmoireGreenKiteText": "Grüner Drachen",
|
||||
"weaponArmoireGreenKiteNotes": "Einen schöneren Drachen findet man kaum, in grün und gelb, es ist ein Traum. Erhöht alle Werte um jeweils <%= attrs %> . Verzauberter Kleiderschrank: Drachen Set (Gegenstand 2 von 5)",
|
||||
"weaponArmoireGreenKiteNotes": "Einen schöneren Drachen findet man kaum, in grün und gelb, es ist ein Traum. Erhöht alle Werte um jeweils <%= attrs %> . Verzauberter Schrank: Drachen Set (Gegenstand 2 von 5)",
|
||||
"weaponArmoireOrangeKiteText": "Oranger Drachen",
|
||||
"weaponArmoireOrangeKiteNotes": "Mit Farben wie der Aufgang und Untergang der Sonne, hoch zu fliegen ist für diesen Drachen eine Wonne. Erhöht alle Werte um jeweils <%= attrs %> . Verzauberter Kleiderschrank: Drachen Set (Gegenstand 3 von 5)",
|
||||
"weaponArmoireOrangeKiteNotes": "Mit Farben wie der Aufgang und Untergang der Sonne, hoch zu fliegen ist für diesen Drachen eine Wonne. Erhöht alle Werte um jeweils <%= attrs %> . Verzauberter Schrank: Drachen Set (Gegenstand 3 von 5)",
|
||||
"weaponArmoirePinkKiteText": "Pinker Drachen",
|
||||
"weaponArmoirePinkKiteNotes": "Er steigt auf , schießt zu Boden, dreht sich flink, dein Drachen im leuchtenden Pink. Erhöht alle Werte um jeweils <%= attrs %> . Verzauberter Kleiderschrank: Drachen Set (Gegenstand 4 von 5)",
|
||||
"weaponArmoirePinkKiteNotes": "Er steigt auf , schießt zu Boden, dreht sich flink, dein Drachen im leuchtenden Pink. Erhöht alle Werte um jeweils <%= attrs %> . Verzauberter Schrank: Drachen Set (Gegenstand 4 von 5)",
|
||||
"weaponArmoireYellowKiteText": "Gelber Drachen",
|
||||
"weaponArmoireYellowKiteNotes": "Er saust am Himmel hin und her, das fällt dem heiteren Drachen nicht schwer. Erhöht alle Werte um jeweils <%= attrs %> . Verzauberter Kleiderschrank: Drachen Set (Gegenstand 5 von 5)"
|
||||
"weaponArmoireYellowKiteNotes": "Er saust am Himmel hin und her, das fällt dem heiteren Drachen nicht schwer. Erhöht alle Werte um jeweils <%= attrs %> . Verzauberter Schrank: Drachen Set (Gegenstand 5 von 5)"
|
||||
}
|
||||
|
||||
@@ -604,7 +604,7 @@
|
||||
"cuddleBuddiesText": "\"Kuschelkumpel\" Quest-Paket",
|
||||
"cuddleBuddiesNotes": "Beinhaltet 'Das Killerkaninchen', 'Das Ruchlose Frettchen' und 'Die Meerschweinchen Gang'. Verfügbar bis zum 31. März.",
|
||||
"aquaticAmigosText": "\"Feuchte Freunde\" Quest-Paket",
|
||||
"aquaticAmigosNotes": "Beinhaltet 'Der magische Axolotl', 'Der Kraken von Unfertik' und 'Der Ruf des Octothulu'. Verfügbar bis zum 31. August.",
|
||||
"aquaticAmigosNotes": "Beinhaltet 'Der magische Axolotl', 'Der Kraken von Unfertik' und 'Der Ruf des Octothulu'. Verfügbar bis zum 30. Juni.",
|
||||
"questSeaSerpentText": "Gefahr in der Tiefe: Seeschlangen-Angriff!",
|
||||
"questSeaSerpentNotes": "Du fühlst Deine Glückssträhne - es ist die perfekte Zeit für einen Ausflug zur Seepferdchen-Rennstrecke. Du steigst in das U-Boot bei Diligent Docks ein und machst Dich bereit für die Reise nach Dilatory, aber kaum bist Du untergetaucht, erschüttert ein Aufprall das U-Boot und lässt seine Insassen stolpern. “Was ist los?” schreit @AriesFaries.<br><br>Du schaust durch ein nahegelegenes Bullauge und bist schockiert von der Wand aus schimmernden Schuppen, die an ihm vorbeizieht. “Seeschlange!” ruft Captain @Witticaster über die Gegensprechanlage aus. “Haltet euch fest, sie kommt schon wieder!” Während Du Dich an die Armlehnen Deines Sitzes klammerst, ziehen Deine unerledigten Aufgaben vor Deinen Augen vorüber. “Vielleicht, wenn wir zusammen arbeiten und sie erledigen”, denkst Du, “können wir dieses Monster vertreiben!”",
|
||||
"questSeaSerpentCompletion": "Von Deiner Hingabe angeschlagen, flieht die Seeschlange und verschwindet in den Tiefen. Als Du in Dilatory ankommst, entfährt Dir ein Seufzer der Erleichterung, bevor Du bemerkst, dass @*~Seraphina~ sich mit drei durchsichtigen Eiern in ihren Armen nähert. “Hier, die hier sollst Du haben”, sagt sie. “Du weißt, wie man mit einer Seeschlange umgeht!” Als Du die Eier annimmst, gelobst Du von neuem, standhaft bei der Erfüllung Deiner Aufgaben zu bleiben, um sicherzustellen, dass es nicht zu einer Wiederholung kommt.",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"step1": "Βήμα 1: Εισάγετε Αποστολές",
|
||||
"webStep1Text": "Το Habitica δεν είναι τίποτα χωρίς στόχους στον πραγματικό κόσμο, οπότε θέσε μερικούς. Μπορείς να προσθέσεις περισσότερους αργότερα! Οι στόχοι μπορούν να προστεθούν πατώντας το πράσινο κουμπί \"Δημιουργία\".\n* **Ρύθμισε τις [Υποχρεώσεις σου](http://habitica.wikia.com/wiki/To-Dos):** Βάλε στόχους που θέλεις να υλοποιείς σπάνια ή μια μόνο φορά στη στήλη των Υποχρεώσεων, έναν κάθε φορά. Μπορείς να τροποποιήσεις τους στόχους κάνοντας κλικ πάνω τους και να προσθέσεις λίστες, ημερομηνίες και άλλα!\n* **Ρύθμισε τους [Καθημερινούς Στόχους](http://habitica.wikia.com/wiki/Dailies):** Πρόσθεσε δραστηριότητες που πρέπει να κάνεις καθημερινά, ή μια συγκεκριμένη μέρα της εβδομάδας, μήνα ή του χρόνου στη στήλη με τις Καθημερινές Υποχρεώσεις. Κάνε κλικ σε έναν στόχο για να τροποποιήσεις το πότε πρέπει να τον ολοκληρώσεις, ή να ορίσεις μια ημερομηνία εκκίνησης. Μπορείς επίσης να ορίσεις μια ημερομηνία ολοκλήρωσης σε επαναλαμβανόμενη βάση, για παράδειγμα, κάθε 3 μέρες.\n* **Ρύθμισε τις [Συνήθειες](http://habitica.wikia.com/wiki/Habits):** Πρόσθεσε Συνήθειες που θέλεις να υιοθετήσεις στη στήλη των Συνηθειών. Μπορείς να τροποποιήσεις μια Συνήθεια ώστε να την θέσεις ως καλή :heavy_plus_sign: η κακή συνήθεια :heavy_minus_sign:\n* **Ρύθμισε τις [Ανταμοιβές](http://habitica.wikia.com/wiki/Rewards):** Επιπλέον από τις Ανταμοιβές που υπάρχουν μέσα στην εφαρμογή, πρόσθεσε δραστηριότητες ή κεράσματα τα οποία θέλεις να χρησιμοποιήσεις ως κίνητρο στην στήλη των Ανταμοιβών. Είναι σημαντικό να κάνεις ένα διάλειμμα ή να επιτρέπεις στον εαυτό σου λίγη ικανοποίηση με μέτρο!\n* Αν χρειάζεσαι έμπνευση για να προσθέσεις στόχους, μπορείς να κοιτάξεις στις σελίδες του wiki για τις [Παραδείγματα για Συνήθειες](http://habitica.wikia.com/wiki/Sample_Habits), [Παραδείγματα Καθημερινών Στόχων](http://habitica.wikia.com/wiki/Sample_Dailies), [Παραδείγματα Υποχρεώσεων](http://habitica.wikia.com/wiki/Sample_To-Dos), and [Παραδείγματα Ανταμειβών](http://habitica.wikia.com/wiki/Sample_Custom_Rewards).",
|
||||
"step2": "Βήμα 2: Πάρτε Πόντους Κάνοντας Πράξεις στην Πραγματική Ζωή",
|
||||
"webStep2Text": "Now, start tackling your goals from the list! As you complete tasks and check them off in Habitica, you will gain [Experience](http://habitica.wikia.com/wiki/Experience_Points), which helps you level up, and [Gold](http://habitica.wikia.com/wiki/Gold_Points), which allows you to purchase Rewards. If you fall into bad habits or miss your Dailies, you will lose [Health](http://habitica.wikia.com/wiki/Health_Points). In that way, the Habitica Experience and Health bars serve as a fun indicator of your progress toward your goals. You'll start seeing your real life improve as your character advances in the game.",
|
||||
"webStep2Text": "Τώρα, ξεκίνα να κυνηγάς τους στόχους σου από τη λίστα! Όσο ολοκληρώνεις και τσεκάρεις στόχους στο Habitica, θα κερδίζεις [Πόντους Εμπειρίας](http://habitica.wikia.com/wiki/Experience_Points), πράγμα που θα σε βοηθήσει να ανεβαίνεις επίπεδα, και [Χρυσό](http://habitica.wikia.com/wiki/Gold_Points), που σου επιτρέπει να αγοράζεις Ανταμειβές. Αν επιστρέψεις σε κακές συνήθειες, ή αν αποτύχεις στους καθημερινούς στόχους σου, θα χάσεις [Ζωή](http://habitica.wikia.com/wiki/Health_Points). Με αυτόν τον τρόπο, η Εμπειρία Habitica και οι μπάρες Ζωής, λειτουργούν ως μια διασκεδαστική ένδειξη της προόδου σου προς τους στόχους σου. Θα αρχίσεις να βλέπεις την πραγματική σου ζωή να βελτιώνεται όσο ο χαρακτήρας σου προχωρά στο παιχνίδι.",
|
||||
"step3": "Βήμα 3: Προσαρμόστε και Εξερευνήστε το Habitica",
|
||||
"webStep3Text": "Once you're familiar with the basics, you can get even more out of Habitica with these nifty features:\n * Organize your tasks with [tags](http://habitica.wikia.com/wiki/Tags) (edit a task to add them).\n * Customize your [avatar](http://habitica.wikia.com/wiki/Avatar) by clicking the user icon in the upper-right corner.\n * Buy your [Equipment](http://habitica.wikia.com/wiki/Equipment) under Rewards or from the [Shops](<%= shopUrl %>), and change it under [Inventory > Equipment](<%= equipUrl %>).\n * Connect with other users via the [Tavern](http://habitica.wikia.com/wiki/Tavern).\n * Starting at Level 3, hatch [Pets](http://habitica.wikia.com/wiki/Pets) by collecting [eggs](http://habitica.wikia.com/wiki/Eggs) and [hatching potions](http://habitica.wikia.com/wiki/Hatching_Potions). [Feed](http://habitica.wikia.com/wiki/Food) them to create [Mounts](http://habitica.wikia.com/wiki/Mounts).\n * At level 10: Choose a particular [class](http://habitica.wikia.com/wiki/Class_System) and then use class-specific [skills](http://habitica.wikia.com/wiki/Skills) (levels 11 to 14).\n * Form a party with your friends (by clicking [Party](<%= partyUrl %>) in the navigation bar) to stay accountable and earn a Quest scroll.\n * Defeat monsters and collect objects on [quests](http://habitica.wikia.com/wiki/Quests) (you will be given a quest at level 15).",
|
||||
"overviewQuestions": "Have questions? Check out the [FAQ](<%= faqUrl %>)! If your question isn't mentioned there, you can ask for further help in the [Habitica Help guild](<%= helpGuildUrl %>).\n\nGood luck with your tasks!"
|
||||
|
||||
@@ -795,6 +795,14 @@
|
||||
"backgroundSailboatAtSunsetText": "Sailboat At Sunset",
|
||||
"backgroundSailboatAtSunsetNotes": "Enjoy the beauty of a sailboat at sunset.",
|
||||
|
||||
"backgrounds072022": "SET 98: Released July 2022",
|
||||
"backgroundBioluminescentWavesText": "Bioluminescent Waves",
|
||||
"backgroundBioluminescentWavesNotes": "Admire the glow of Bioluminescent Waves.",
|
||||
"backgroundUnderwaterCaveText": "Underwater Cave",
|
||||
"backgroundUnderwaterCaveNotes": "Explore an Underwater Cave.",
|
||||
"backgroundUnderwaterStatuesText": "Underwater Statue Garden",
|
||||
"backgroundUnderwaterStatuesNotes": "Try not to blink in an Underwater Statue Garden.",
|
||||
|
||||
"timeTravelBackgrounds": "Steampunk Backgrounds",
|
||||
"backgroundAirshipText": "Airship",
|
||||
"backgroundAirshipNotes": "Become a sky sailor on board your very own Airship.",
|
||||
|
||||
@@ -428,7 +428,7 @@
|
||||
|
||||
"weaponSpecialSummer2022RogueText": "Crab Claw",
|
||||
"weaponSpecialSummer2022RogueNotes": "If you're in a pinch, don't hesitate to show these fearsome claws! Increases Strength by <%= str %>. Limited Edition 2022 Summer Gear.",
|
||||
"weaponSpecialSummer2022WarriorText": "Cyclone Shield",
|
||||
"weaponSpecialSummer2022WarriorText": "Whirling Cyclone",
|
||||
"weaponSpecialSummer2022WarriorNotes": "It spins! It redirects! And it brings the storm! Increases Strength by <%= str %>. Limited Edition 2022 Summer Gear.",
|
||||
"weaponSpecialSummer2022MageText": "Manta Ray Staff",
|
||||
"weaponSpecialSummer2022MageNotes": "Magically clear the waters ahead of you with one swirl of this staff. Increases Intelligence by <%= int %> and Perception by <%= per %>. Limited Edition 2022 Summer Gear.",
|
||||
@@ -1073,7 +1073,7 @@
|
||||
"armorSpecialSummer2022WarriorText": "Waterspout Armor",
|
||||
"armorSpecialSummer2022WarriorNotes": "Get ready for a watery battle as you surround yourself with this twirling, whirling column of air and mist. Increases Constitution by <%= con %>. Limited Edition 2022 Summer Gear.",
|
||||
"armorSpecialSummer2022MageText": "Manta Ray Armor",
|
||||
"armorSpecialSummer2022MageNotes": "Keep your head protected as you dive into your tasks or into the deepest waters. Increases Intelligence by <%= int %>. Limited Edition 2022 Summer Gear.",
|
||||
"armorSpecialSummer2022MageNotes": "When wearing this armor, you will glide easily through your work like the manta ray glides through water. Increases Intelligence by <%= int %>. Limited Edition 2022 Summer Gear.",
|
||||
"armorSpecialSummer2022HealerText": "Angelfish Tail",
|
||||
"armorSpecialSummer2022HealerNotes": "Use your colorful fins to scoot about the reef and help those in need of rest and healing. Increases Constitution by <%= con %>. Limited Edition 2022 Summer Gear.",
|
||||
|
||||
@@ -1185,6 +1185,8 @@
|
||||
"armorMystery202112Notes": "Glide through icy seas and never get cold with this glimmering tail. Confers no benefit. December 2021 Subscriber Item.",
|
||||
"armorMystery202204Text": "Virtual Adventurer Capsule",
|
||||
"armorMystery202204Notes": "Looks like doing your tasks now requires pushing these mysterious buttons! What could they do? Confers no benefit. April 2022 Subscriber Item.",
|
||||
"armorMystery202207Text": "Jammin' Jelly Armor",
|
||||
"armorMystery202207Notes": "This armor will have you looking glamorous and gelatinous. Confers no benefit. July 2022 Subscriber Item.",
|
||||
"armorMystery301404Text": "Steampunk Suit",
|
||||
"armorMystery301404Notes": "Dapper and dashing, wot! Confers no benefit. February 3015 Subscriber Item.",
|
||||
"armorMystery301703Text": "Steampunk Peacock Gown",
|
||||
@@ -1360,6 +1362,8 @@
|
||||
"armorArmoireGardenersOverallsNotes": "Don’t be afraid to work down in the dirt when you’re wearing these durable overalls. Increases Constitution by <%= con %>. Enchanted Armoire: Gardener Set (Item 1 of 4).",
|
||||
"armorArmoireStrawRaincoatText": "Straw Raincoat",
|
||||
"armorArmoireStrawRaincoatNotes": "This woven straw cape will keep you dry and your armor from rusting while on your quest. Just don’t venture too near a candle! Increases Constitution by <%= con %>. Enchanted Armoire: Straw Raincoat Set (Item 1 of 2).",
|
||||
"armorArmoireFancyPirateSuitText": "Fancy Pirate Jacket",
|
||||
"armorArmoireFancyPirateSuitNotes": "Wear this fine jacket well as you organize your ship’s library or talk it through as a crew. Increases Constitution and Intelligence by <%= attrs %> each. Enchanted Armoire: Fancy Pirate Set (Item 1 of 3).",
|
||||
|
||||
"headgear": "helm",
|
||||
"headgearCapitalized": "Headgear",
|
||||
@@ -1750,7 +1754,7 @@
|
||||
"headSpecialSummer2022RogueText": "Crab Helm",
|
||||
"headSpecialSummer2022RogueNotes": "No time to be crabby, we're out here shellebrating the summer's hottest crustacean puns. Increases Perception by <%= per %>. Limited Edition 2022 Summer Gear.",
|
||||
"headSpecialSummer2022WarriorText": "Waterspout Helm",
|
||||
"headSpecialSummer2022WarriorNotes": "Channel the power of water as you center yourself in this this intense vortex. Increases Strength by <%= str %>. Limited Edition 2022 Summer Gear.",
|
||||
"headSpecialSummer2022WarriorNotes": "Channel the power of water as you center yourself in this intense vortex. Increases Strength by <%= str %>. Limited Edition 2022 Summer Gear.",
|
||||
"headSpecialSummer2022MageText": "Manta Ray Helm",
|
||||
"headSpecialSummer2022MageNotes": "Keep your head protected as you dive into your tasks or into the deepest waters. Increases Perception by <%= per %>. Limited Edition 2022 Summer Gear.",
|
||||
"headSpecialSummer2022HealerText": "Angelfish Ear Fins",
|
||||
@@ -1918,6 +1922,11 @@
|
||||
"headMystery202202Notes": "You gotta have blue hair! Confers no benefit. February 2022 Subscriber Item.",
|
||||
"headMystery202206Text": "Sea Sprite Circlet",
|
||||
"headMystery202206Notes": "The blue pearl in this circlet grants you waterbending powers. Use them wisely! Confers no benefit. June 2022 Subscriber Item.",
|
||||
"headMystery202207Text": "Jammin' Jelly Helm",
|
||||
"headMystery202207Notes": "Need a hand with your tasks? Will several dozen bioluminescent tentacles do? Confers no benefit. July 2022 Subscriber Item.",
|
||||
"headMystery202208Text": "Perky Ponytail",
|
||||
"headMystery202208Notes": "Enjoy showing off this voluminous hair - it can double as a whip in a pinch! Confers no benefit. August 2022 Subscriber Item.",
|
||||
|
||||
"headMystery301404Text": "Fancy Top Hat",
|
||||
"headMystery301404Notes": "A fancy top hat for the finest of gentlefolk! January 3015 Subscriber Item. Confers no benefit.",
|
||||
"headMystery301405Text": "Basic Top Hat",
|
||||
@@ -2091,6 +2100,8 @@
|
||||
"headArmoireGardenersSunHatNotes": "The bright light of the day star won’t shine in your eyes when you wear this wide-brimmed hat. Increases Perception by <%= per %>. Enchanted Armoire: Gardener Set (Item 2 of 4).",
|
||||
"headArmoireStrawRainHatText": "Straw Rain Hat",
|
||||
"headArmoireStrawRainHatNotes": "You’ll be able to spot every obstacle in your path when you wear this water-resistant, conical hat. Increases Perception by <%= per %>. Enchanted Armoire: Straw Raincoat Set (Item 2 of 2).",
|
||||
"headArmoireFancyPirateHatText": "Fancy Pirate Hat",
|
||||
"headArmoireFancyPirateHatNotes": "Be protected from the sun and any seagulls flying overhead as you drink tea on the deck of your ship. Increases Perception by <%= per %>. Enchanted Armoire: Fancy Pirate Set (Item 2 of 3).",
|
||||
|
||||
"offhand": "off-hand item",
|
||||
"offHandCapitalized": "Off-Hand Item",
|
||||
@@ -2323,7 +2334,7 @@
|
||||
"shieldSpecialSpring2022HealerText": "Peridot Shield",
|
||||
"shieldSpecialSpring2022HealerNotes": "Formed by molten rock of the upper mantle, this shield can withstand any hit that comes its way. Increases Constitution by <%= con %>. Limited Edition 2022 Spring Gear.",
|
||||
|
||||
"shieldSpecialSummer2022WarriorText": "Shark Blade",
|
||||
"shieldSpecialSummer2022WarriorText": "Feisty Shark",
|
||||
"shieldSpecialSummer2022WarriorNotes": "It snaps! It bites! And it never, ever stops! Increases Constitution by <%= con %>. Limited Edition 2022 Summer Gear.",
|
||||
"shieldSpecialSummer2022HealerText": "Remedial Ripples",
|
||||
"shieldSpecialSummer2022HealerNotes": "Send out restorative magic in gentle ripples through the reef. Increases Constitution by <%= con %>. Limited Edition 2022 Summer Gear.",
|
||||
@@ -2477,6 +2488,8 @@
|
||||
"shieldArmoireSpanishGuitarNotes": "Tink! Tink! Thrummm! Gather your party for a concert or celebration by playing this guitar. Increases Perception by <%= per %> and Intelligence by <%= int %>. Enchanted Armoire: Musical Instrument Set 1 (Item 2 of 3)",
|
||||
"shieldArmoireSnareDrumText": "Snare Drum",
|
||||
"shieldArmoireSnareDrumNotes": "Rat-a-tat-tat! Gather your party for a parade or march into battle by playing this drum. Increases Constitution by <%= con %> and Intelligence by <%= int %>. Enchanted Armoire: Musical Instrument Set 1 (Item 3 of 3)",
|
||||
"shieldArmoireTreasureMapText": "Treasure Map",
|
||||
"shieldArmoireTreasureMapNotes": "X marks the spot! You never know what you’ll find when you follow this handy map to fabled treasures: gold, jewels, relics, or perhaps a petrified orange? Increases Strength and Intelligence by <%= attrs %> each. Enchanted Armoire: Fancy Pirate Set (Item 3 of 3).",
|
||||
|
||||
"back": "Back Accessory",
|
||||
"backBase0Text": "No Back Accessory",
|
||||
@@ -2829,6 +2842,8 @@
|
||||
"eyewearMystery202204ANotes": "What's your mood today? Express yourself with these fun screens. Confers no benefit. April 2022 Subscriber Item.",
|
||||
"eyewearMystery202204BText": "Virtual Face",
|
||||
"eyewearMystery202204BNotes": "What's your mood today? Express yourself with these fun screens. Confers no benefit. April 2022 Subscriber Item.",
|
||||
"eyewearMystery202208Text": "Sparkly Eyes",
|
||||
"eyewearMystery202208Notes": "Lull your enemies into a false sense of security with these terrifyingly cute peepers. Confers no benefit. August 2022 Subscriber Item.",
|
||||
"eyewearMystery301404Text": "Eyewear Goggles",
|
||||
"eyewearMystery301404Notes": "No eyewear could be fancier than a pair of goggles - except, perhaps, for a monocle. Confers no benefit. April 3015 Subscriber Item.",
|
||||
"eyewearMystery301405Text": "Monocle",
|
||||
|
||||
@@ -129,6 +129,7 @@
|
||||
"sendGiftHeading": "Send Gift to <%= name %>",
|
||||
"sendGiftGemsBalance": "From <%= number %> Gems",
|
||||
"sendGiftCost": "Total: $<%= cost %> USD",
|
||||
"sendGiftTotal": "Total:",
|
||||
"sendGiftFromBalance": "From Balance",
|
||||
"sendGiftPurchase": "Purchase",
|
||||
"sendGiftMessagePlaceholder": "Personal message (optional)",
|
||||
@@ -363,5 +364,6 @@
|
||||
"managerNotes": "Manager's Notes",
|
||||
"assignedDateOnly": "Assigned on <strong><%= date %></strong>",
|
||||
"assignedDateAndUser": "Assigned by <strong>@<%- username %></strong> on <strong><%= date %></strong>",
|
||||
"claimRewards": "Claim Rewards"
|
||||
"claimRewards": "Claim Rewards",
|
||||
"chatTemporarilyUnavailable": "Chat is temporarily unavailable. Please try again later."
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
"passwordChangeSuccess": "Your password was successfully changed to the one you just chose. You can now use it to access your account.",
|
||||
"displayNameSuccess": "Display name successfully changed",
|
||||
"emailSuccess": "Email successfully changed",
|
||||
"passwordSuccess": "Password successfully changed",
|
||||
"detachSocial": "De-register <%= network %>",
|
||||
"detachedSocial": "Successfully removed <%= network %> authentication from your account",
|
||||
"addedLocalAuth": "Successfully added local authentication",
|
||||
@@ -124,6 +125,7 @@
|
||||
"unsubscribeAllPush": "Check to Unsubscribe from all Push Notifications",
|
||||
"correctlyUnsubscribedEmailType": "Correctly unsubscribed from \"<%= emailType %>\" emails.",
|
||||
"subscriptionRateText": "Recurring <strong>$<%= price %> USD</strong> every <strong><%= months %> months</strong>",
|
||||
"giftSubscriptionRateText": "<strong>$<%= price %> USD</strong> for <strong><%= months %> months</strong>",
|
||||
"benefits": "Benefits",
|
||||
"coupon": "Coupon",
|
||||
"couponText": "We sometimes have events and give out promo codes for special gear. (eg, those who stop by our Wondercon booth)",
|
||||
@@ -203,11 +205,13 @@
|
||||
"transaction_gift_send": "Gifted to",
|
||||
"transaction_gift_receive": "Received from",
|
||||
"transaction_create_challenge": "Created challenge",
|
||||
"transaction_create_bank_challenge": "Created bank challenge",
|
||||
"transaction_create_guild": "Created guild",
|
||||
"transaction_change_class": "Changed class",
|
||||
"transaction_rebirth": "Used Orb of Rebirth",
|
||||
"transaction_release_pets": "Released pets",
|
||||
"transaction_release_mounts": "Released mounts",
|
||||
"transaction_reroll": "Used Fortify Potion",
|
||||
"transaction_subscription_perks": "From subscription perk"
|
||||
"transaction_subscription_perks": "From subscription perk",
|
||||
"transaction_admin_update_balance": "Admin given"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
"subscriptions": "Subscriptions",
|
||||
"viewSubscriptions": "View Subscriptions",
|
||||
"sendGems": "Send Gems",
|
||||
"howManyGemsPurchase": "How many Gems would you like to purchase?",
|
||||
"howManyGemsSend":"How many Gems would you like to send?",
|
||||
"needToPurchaseGems": "Need to purchase Gems as a gift?",
|
||||
"wantToSendOwnGems": "Want to send your own Gems?",
|
||||
"buyGemsGold": "Buy Gems with Gold",
|
||||
"mustSubscribeToPurchaseGems": "Must subscribe to purchase gems with GP",
|
||||
"reachedGoldToGemCapQuantity": "Your requested amount <%= quantity %> exceeds the amount you can buy for this month (<%= convCap %>). The full amount becomes available within the first three days of each month. Thanks for subscribing!",
|
||||
@@ -135,6 +139,8 @@
|
||||
"mysterySet202204": "Virtual Adventurer Set",
|
||||
"mysterySet202205": "Dusk-Winged Dragon Set",
|
||||
"mysterySet202206": "Sea Sprite Set",
|
||||
"mysterySet202207": "Jammin' Jelly Set",
|
||||
"mysterySet202208": "Perky Ponytail Set",
|
||||
"mysterySet301404": "Steampunk Standard Set",
|
||||
"mysterySet301405": "Steampunk Accessories Set",
|
||||
"mysterySet301703": "Peacock Steampunk Set",
|
||||
@@ -197,5 +203,6 @@
|
||||
"needToUpdateCard": "Need to update your card?",
|
||||
"readyToResubscribe": "Are you ready to resubscribe?",
|
||||
"cancelYourSubscription": "Cancel your subscription?",
|
||||
"cancelSubAlternatives": "If you're having technical problems or Habitica doesn't seem to be working out for you, please consider <a href='mailto:admin@habitica.com'>contacting us</a>. We want to help you get the most from Habitica."
|
||||
"cancelSubAlternatives": "If you're having technical problems or Habitica doesn't seem to be working out for you, please consider <a href='mailto:admin@habitica.com'>contacting us</a>. We want to help you get the most from Habitica.",
|
||||
"sendAGift": "Send Gift"
|
||||
}
|
||||
|
||||
@@ -105,19 +105,19 @@
|
||||
"weaponSpecialRoguishRainbowMessageText": "Roguish Rainbow Message",
|
||||
"weaponSpecialRoguishRainbowMessageNotes": "This sparkly envelope contains messages of encouragement from Habiticans, and a touch of magic to help speed your deliveries! Nagtataás ng Pandamá ng <%= per %>.",
|
||||
"weaponSpecialSkeletonKeyText": "Skeleton Key",
|
||||
"weaponSpecialSkeletonKeyNotes": "All the best Sneakthieves carry a key that can open any lock! Nagtataás ng Pangangatawán ng <%= con %>.",
|
||||
"weaponSpecialSkeletonKeyNotes": "Lahát ng mga mahuhusay na Singitpuslít ay may daláng susì na maaaring magbukas ng anumáng <i>candado</i>! Nagtataás ng Pangangatawán ng <%= con %>.",
|
||||
"weaponSpecialNomadsScimitarText": "Nomad's Scimitar",
|
||||
"weaponSpecialNomadsScimitarNotes": "The curved blade of this Scimitar is perfect for attacking Tasks from the back of a mount! Nagtataás ng Katalinuhan ng <%= int %>.",
|
||||
"weaponSpecialNomadsScimitarNotes": "Ang malantík na talim ng Simitar na itó ay napakainam gamiting panambáng ng mga Gawain mulá sa likurán ng sakáy-alagà! Nagtataás ng Katalinuhan ng <%= int %>.",
|
||||
"weaponSpecialFencingFoilText": "Fencing Foil",
|
||||
"weaponSpecialFencingFoilNotes": "Should anyone dare to impugn your honor, you'll be ready with this fine foil! Nagtataás ng Lakás ng <%= str %>.",
|
||||
"weaponSpecialFencingFoilNotes": "Kung may sinumang maglalakás-loób na siraan ang iyóng karangalan, handáng-handá ka gamit ang kahanga-hangang pang-Eskrimang patalím na itó! Nagtataás ng Lakás ng <%= str %>.",
|
||||
"weaponSpecialTachiText": "Tachi",
|
||||
"weaponSpecialTachiNotes": "This light and curved sword will shred your tasks to ribbons! Nagtataás ng Lakás ng <%= str %>.",
|
||||
"weaponSpecialTachiNotes": "Gugutay-gutayín ng magaán at malantík na patalím na itó ang iyong mga Gawain. Nagtataás ng Lakás ng <%= str %>.",
|
||||
"weaponSpecialAetherCrystalsText": "Aether Crystals",
|
||||
"weaponSpecialAetherCrystalsNotes": "These bracers and crystals once belonged to the Lost Masterclasser herself. Nagtataás ng Lahát ng mga Katangian ng <%= attrs %>.",
|
||||
"weaponSpecialAetherCrystalsNotes": "Dating pagmamay-arì mismo ng Ligáw na Dalubhasà ang mga sapín at kristál na itó. Nagtataás ng Lahát ng mga Katangian ng <%= attrs %>.",
|
||||
"weaponSpecialYetiText": "Yeti-Tamer Spear",
|
||||
"weaponSpecialYetiNotes": "This spear allows its user to command any yeti. Nagtataás ng Lakás ng <%= str %>. Biláng na Limbág na Kasangkapan ng Taglamíg ng ng 2013-2014.",
|
||||
"weaponSpecialYetiNotes": "Nagbibigay ang sibát na itó ng kakayahang mag-utos sa anumáng <i>yeti</i>. Nagtataás ng Lakás ng <%= str %>. Biláng na Limbág na Kasangkapan ng Taglamíg ng ng 2013-2014.",
|
||||
"weaponSpecialSkiText": "Ski-sassin Pole",
|
||||
"weaponSpecialSkiNotes": "A weapon capable of destroying hordes of enemies! It also helps the user make very nice parallel turns. Nagtataás ng Lakás ng <%= str %>. Biláng na Limbág na Kasangkapan ng Taglamíg ng ng 2013-2014.",
|
||||
"weaponSpecialSkiNotes": "Isáng sandata na kayang pumuksâ ng mga kuyog ng kalaban! Nakakatulong rin itóng mapahusay ang paglikô sa yelo. Nagtataás ng Lakás ng <%= str %>. Biláng na Limbág na Kasangkapan ng Taglamíg ng ng 2013-2014.",
|
||||
"weaponSpecialCandycaneText": "Candy Cane Staff",
|
||||
"weaponSpecialCandycaneNotes": "A powerful mage's staff. Powerfully DELICIOUS, we mean! Nagtataás ng Katalinuhan ng <%= int %> at Pandamá ng <%= per %>. Biláng na Limbág na Kasangkapan ng Taglamíg ng ng 2013-2014.",
|
||||
"weaponSpecialSnowflakeText": "Bastón ng Kristál na Niyebe",
|
||||
@@ -1953,7 +1953,7 @@
|
||||
"shieldArmoireBaseballGloveNotes": "Perfect for the big tournament, or a friendly game of catch between tasks. Nagtataás ng Lakás ng <%= str %>. Enchanted Armoire: Baseball Set (Item 4 of 4).",
|
||||
"shieldArmoireMeatFoodNotes": "Sometimes a bit of protein is what you need to grow up big and strong. Some of your pets are more eager for it than others! Nagtataás ng Lakás ng <%= str %>. Enchanted Armoire: Pet Food Set (Item 5 of 10).",
|
||||
"shieldArmoireBouncyBubblesNotes": "Complete your relaxing bath with these exuberant bubbles! Nagtataás ng Lakás ng <%= str %>. Enchanted Armoire: Bubble Bath Set (Item 4 of 4).",
|
||||
"weaponSpecialKS2019Notes": "Curved as a gryphon's beak and talons, this ornate polearm reminds you to power through when the task ahead feels daunting. Nagtataás ng Lakás ng <%= str %>.",
|
||||
"weaponSpecialKS2019Notes": "Kasimbalikô ng tukâ at kukó ng <i>gryphon</i>, nagpapaalala ang mapalamutíng sibát na itó na tiyagaín ang mga gawain kapág nakakapanghinang-loób ang mga itó. Nagtataás ng Lakás ng <%= str %>.",
|
||||
"shieldArmoireStrawberryFoodNotes": "A delicious fresh strawberry to feed to your pets! Do you know which pets like strawberries best? Nagtataás ng Lakás ng <%= str %>. Enchanted Armoire: Pet Food Set (Item 1 of 10).",
|
||||
"shieldArmoireBagpipesNotes": "The uncharitable might say you're planning to wake the dead with these bagpipes -- but you know you're just motivating your Party to success! Nagtataás ng Lakás ng <%= str %>. Enchanted Armoire: Bagpiper Set (Item 3 of 3).",
|
||||
"shieldArmoireGardenersSpadeNotes": "Whether you’re digging in the garden, searching for buried treasure, or creating a secret tunnel, this trusty spade is at your side. Nagtataás ng Lakás ng <%= str %>. Enchanted Armoire: Gardener Set (Item 3 of 4).",
|
||||
|
||||
@@ -604,7 +604,7 @@
|
||||
"cuddleBuddiesText": "Lot de quêtes des acolytes à câlins",
|
||||
"cuddleBuddiesNotes": "Contient \"Le lapin tueur\", \"L'abominable furet\", et \"Le gang des cochons d'Inde\". Disponible jusqu'au 31 mars.",
|
||||
"aquaticAmigosText": "Lot de quêtes des amis aquatiques",
|
||||
"aquaticAmigosNotes": "Contient “L’axototl magique”, “Le kraken d’Inkomplet”, et “L’appel d’Octothulu”. Disponible jusqu’au 31 août.",
|
||||
"aquaticAmigosNotes": "Contient “L’axototl magique”, “Le kraken d’Inkomplet”, et “L’appel d’Octothulu”. Disponible jusqu’au 30 juin.",
|
||||
"questSeaSerpentText": "Danger dans les profondeurs : L’attaque du serpent de mer !",
|
||||
"questSeaSerpentNotes": "Vous vous sentez en veine grâce à vos réussites - c'est le moment idéal pour une excursion à l'hippodrome des hippocampes. Vous montez à bord du sous-marin aux Docks Diligents et vous vous installez pour le voyage à Dilatoire, mais vous êtes à peine submergé lorsqu'un impact secoue le sous-marin, et fait chavirer ses occupants. \"Que se passe-t-il ?\"<br><br>Vous regardez à travers un hublot à proximité et vous êtes surpris par le mur d'écailles scintillantes qui passe à côté. \"Serpent de mer !\" crie le capitaine @Witticaster par l'interphone. \"Préparez-vous, il revient !\" Lorsque vous saisissez les bras de votre siège, vos tâches inachevées clignotent devant vos yeux. \"Peut-être que si nous travaillons ensemble et les complétons\", pensez-vous, \"nous pouvons chasser ce monstre !\"",
|
||||
"questSeaSerpentCompletion": "Battus grâce à votre engagement, les serpents de mer fuient, disparaissant dans les profondeurs. Quand vous arrivez à Dilatoire, vous poussez un soupir de soulagement avant de remarquer que @*~Seraphina~ venait vers vous avec trois œufs translucides retenus délicatement dans ses bras. « Tiens, tu mérites de les avoir», dit-elle. « Tu sais comment t’y prendre avec les serpents de mer ! » Comme vous acceptez les œufs, vous faites à nouveau vœu de rester toujours constant dans la réalisation de vos tâches pour s’assurer que l’Histoire ne se répètera pas.",
|
||||
|
||||
@@ -668,8 +668,8 @@
|
||||
"backgrounds012022": "SET 92: Rilasciato Gennaio 2022",
|
||||
"backgroundMeteorShowerNotes": "Osserva l'abbagliante spettacolo notturno di una pioggia di meteoriti.",
|
||||
"backgroundSnowyFarmNotes": "Controlla che tutti stiano bene e al caldo nella tua fattoria coperta di neve.",
|
||||
"backgroundMeteorShowerText": "Pioggia di Metore",
|
||||
"backgroundPalmTreeWithFairyLightsText": "Palma con Lucine",
|
||||
"backgroundMeteorShowerText": "Pioggia di Meteore",
|
||||
"backgroundPalmTreeWithFairyLightsText": "Palma con Luci Fatate",
|
||||
"backgroundPalmTreeWithFairyLightsNotes": "Posa vicino a una palma ornata di luci decorative.",
|
||||
"backgroundSnowyFarmText": "Fattoria Innevata",
|
||||
"backgrounds022022": "SET 93: Rilasciato a febbraio 2022",
|
||||
|
||||
@@ -2534,8 +2534,8 @@
|
||||
"armorArmoireShootingStarCostumeText": "Gonna Stellata",
|
||||
"headSpecialWinter2022RogueText": "Finale Tonante",
|
||||
"armorArmoireShootingStarCostumeNotes": "Apparentemente intessuta a partire dal cielo notturno stesso, questo abito fluido ti consente di aleggiare sopra tutti gli ostacoli sul tuo cammino. Aumenta la Costituzione di <%= con %>. Scrigno Incantato: Set della Polvere di Stella (oggetto 2 di 3).",
|
||||
"weaponArmoireShootingStarSpellText": "Scintille di Polvere di Stella",
|
||||
"weaponArmoireShootingStarSpellNotes": "Avvolgiti in un incantesimo di polvere di stelle per aiutarti a realizzare i tuoi desideri. Aumenta Forza e Intelligenza di <%= attrs %> ciascuno. Scrigno incantato: Set della Polvere di Stella (oggetto 3 di 3).",
|
||||
"weaponArmoireShootingStarSpellText": "Scintille di Polvere di Stelle",
|
||||
"weaponArmoireShootingStarSpellNotes": "Avvolgiti in un incantesimo di polvere di stelle per aiutarti a realizzare i tuoi desideri. Aumenta Forza e Intelligenza di <%= attrs %> ciascuno. Scrigno incantato: Set della Polvere di Stelle (oggetto 3 di 3).",
|
||||
"armorSpecialWinter2022WarriorText": "Calza Sofficiosa",
|
||||
"armorSpecialWinter2022WarriorNotes": "Chi dice che non puoi essere comodo e a tuo agio mentre combatti con le attività quotidiane? Aumenta la Costituzione di <%= con %>. Equipaggiamento in edizione limitata, inverno 2021-2022.",
|
||||
"armorSpecialWinter2022MageText": "Cotta di Maglia Melograno",
|
||||
|
||||
@@ -696,5 +696,12 @@
|
||||
"backgroundAnimalsDenText": "Bosbeest's Hol",
|
||||
"backgroundAnimalsDenNotes": "Beknus je in een Bosbeest's Hol.",
|
||||
"backgroundBrickWallWithIvyText": "Bakstenen Muur met Klimop",
|
||||
"backgroundBrickWallWithIvyNotes": "Bewonder een Bakstenen Muur met Klimop."
|
||||
"backgroundBrickWallWithIvyNotes": "Bewonder een Bakstenen Muur met Klimop.",
|
||||
"backgroundBeachWithDunesText": "Strand met duinen",
|
||||
"backgroundBeachWithDunesNotes": "Ontdek een strand met duinen.",
|
||||
"backgroundMountainWaterfallText": "Berg Waterval",
|
||||
"backgroundMountainWaterfallNotes": "Bewonder een berg waterval.",
|
||||
"backgroundSailboatAtSunsetText": "Zeilboot Bij Zonsondergang",
|
||||
"backgroundSailboatAtSunsetNotes": "Geniet van de schoonheid van een zeilboot tijdens zonsondergang.",
|
||||
"backgrounds062022": "SET 97: uitgebracht in juni 2022"
|
||||
}
|
||||
|
||||
@@ -1175,7 +1175,7 @@
|
||||
"headArmoireRedHairbowText": "Rode strik",
|
||||
"headArmoireRedHairbowNotes": "Word sterk, stoer en slim door het dragen van deze prachtige rode haarband! Verhoogt Kracht met <%= str %>, Weerbaarheid met <%= con %> en Intelligentie met <%= int %>. Betoverd kabinet: Rode haarbandset (voorwerp 1 van 2).",
|
||||
"headArmoireVioletFloppyHatText": "Slappe paarse hoed",
|
||||
"headArmoireVioletFloppyHatNotes": "Deze simpele hoed is doorweven met vele toverspreuken, waardoor hij een aangename paarse kleur heeft gekregen. Verhoogt Perceptie met <%= per %>, Intelligentie met <%= int %> en Weerbaarheid met <%= con %>. Betoverd kabinet: onafhankelijk voorwerp.",
|
||||
"headArmoireVioletFloppyHatNotes": "Deze simpele hoed is doorweven met vele toverspreuken, waardoor hij een aangename paarse kleur heeft gekregen. Verhoogt Perceptie met <%= per %>, Intelligentie met <%= int %> en Weerbaarheid met <%= con %>. Betoverd kabinet: Violette Loungewear (voorwerp 1 van 3).",
|
||||
"headArmoireGladiatorHelmText": "Gladiatorenhelm",
|
||||
"headArmoireGladiatorHelmNotes": "Om en gladiator te zijn moet je niet alleen sterk zijn... maar ook geslepen. Vergroot intelligentie met <%= int %> en perceptie met <%= per %>. Betoverd kabinet: gladiatorset (voorwerp 1 van 3).",
|
||||
"headArmoireRancherHatText": "Cowboyhoed",
|
||||
@@ -1611,7 +1611,7 @@
|
||||
"bodyMystery201901Notes": "These shimmering pauldrons are strong, but will rest on your shoulders as weightlessly as a ray of dancing light. Confers no benefit. January 2019 Subscriber Item.",
|
||||
"bodyArmoireCozyScarfText": "Knusse Sjaal",
|
||||
"bodyArmoireCozyScarfNotes": "This fine scarf will keep you warm as you go about your wintry business. Increases Constitution and Perception by <%= attrs %> each. Enchanted Armoire: Lamplighter's Set (Item 4 of 4).",
|
||||
"headAccessory": "hoofdaccessoire",
|
||||
"headAccessory": "Hoofdaccessoire",
|
||||
"headAccessoryCapitalized": "Hoofdaccessoire",
|
||||
"accessories": "Accessoires",
|
||||
"animalEars": "Dierenoren",
|
||||
@@ -2396,5 +2396,7 @@
|
||||
"weaponSpecialSpring2022RogueNotes": "Een glanzende! Het is zo glimmend and glanzend en mooi en leuk en helemaal van jou! Verhoogt Kracht met <%= str %>. Beperkte oplage 2022 lenteuitrusting.",
|
||||
"weaponSpecialSpring2022WarriorText": "Binnenstebuiten Paraplu",
|
||||
"weaponSpecialSpring2022WarriorNotes": "Jakkes! Die wind was misschien iets sterker dan je dacht, he? Verhoogt Kracht met <%= str %>. Beperkte oplage 2022 lenteuitrusting.",
|
||||
"weaponSpecialSpring2022MageText": "Forsythia Staf"
|
||||
"weaponSpecialSpring2022MageText": "Forsythia Staf",
|
||||
"armorArmoireSoftVioletSuitNotes": "Paars is een luxe kleur. Ontspan in stijl na je al je dagelijke taken hebt volbracht. Verhoogt Weerbaarheid en Kracht met <%= attrs %> elk. Betoverde kast: Violette Loungewear (voorwerp 2 van 3).",
|
||||
"shieldArmoireSoftVioletPillowNotes": "De slimme krijger pakt een kussen in voor elke expeditie. Bescherm jezelf van door uitstel veroorzaakte paniek... zelfs terwijl je een dutje doet. Verhoogt Intelligentie met <%= int %>. Betoverde kast: Violette Loungewear (voorwerp 3 van 3)."
|
||||
}
|
||||
|
||||
@@ -105,9 +105,14 @@
|
||||
"achievementSeeingRed": "Exército Vermelho",
|
||||
"achievementSkeletonCrew": "Equipe Esqueleto",
|
||||
"achievementBugBonanza": "Prosperidade de Inseto",
|
||||
"achievementRosyOutlook": "Aspecto Rosado",
|
||||
"achievementRosyOutlook": "Perspectiva Rosada",
|
||||
"achievementVioletsAreBlue": "Violetas são Azuis",
|
||||
"achievementSeasonalSpecialist": "Especialista Sazonal",
|
||||
"achievementWildBlueYonderModalText": "Tu domesticaste todas as Montarias de Algodão Doce Azul!",
|
||||
"achievementSeasonalSpecialistText": "Completou todas as missões sazonais de Primavera e Inverno: Caçada aos Ovos, Noel Caçador, e Encontre o Filhote!"
|
||||
"achievementSeasonalSpecialistText": "Completou todas as missões sazonais de Primavera e Inverno: Caça aos Ovos, Pai Natal Caçador, e Encontre o Filhote!",
|
||||
"achievementDomesticatedText": "Eclodiu todas as cores padrão das mascotes domesticadas: Furão, Poquinho-da-Índia, Galo, Porco Voador, Rato, Coelhinho, Cavalo e Vaca!",
|
||||
"achievementDomesticated": "I-A-I-A-OH",
|
||||
"achievementVioletsAreBlueModalText": "Coletou todas as Mascotes Algodão-doce Rosa!",
|
||||
"achievementDomesticatedModalText": "Coletou todas as mascotes domesticadas!",
|
||||
"achievementWildBlueYonderText": "Domesticou todas as Montarias de Algodão Doce Azul."
|
||||
}
|
||||
|
||||
@@ -132,5 +132,7 @@
|
||||
"achievementBirdsOfAFeatherModalText": "Você coletou todos os mascotes voadores!",
|
||||
"achievementGroupsBeta2022Text": "Você e seu grupo deram um feedback inestimável para ajudar a testar o Habitica.",
|
||||
"achievementGroupsBeta2022ModalText": "Você e seu grupo ajudaram o Habitica, testando e dando o seu feedback!",
|
||||
"achievementReptacularRumbleModalText": "Você coletou todos os mascotes do tipo réptil!"
|
||||
"achievementReptacularRumbleModalText": "Você coletou todos os mascotes do tipo réptil!",
|
||||
"achievementReptacularRumble": "Répteis Reptumbantes",
|
||||
"achievementReptacularRumbleText": "Coletou todos os mascotes comuns do tipo réptil: Cobra, Jacaré, Pterodáctilo, Tartaruga, Tiranossauro, Tricerátops e Velociraptor!"
|
||||
}
|
||||
|
||||
@@ -505,6 +505,11 @@ const backgrounds = {
|
||||
mountain_waterfall: { },
|
||||
sailboat_at_sunset: { },
|
||||
},
|
||||
backgrounds072022: {
|
||||
bioluminescent_waves: { },
|
||||
underwater_cave: { },
|
||||
underwater_statues: { },
|
||||
},
|
||||
timeTravelBackgrounds: {
|
||||
airship: {
|
||||
price: 1,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import t from '../translation';
|
||||
import prefill from './prefill';
|
||||
import { EVENTS } from '../constants';
|
||||
|
||||
export default prefill({
|
||||
baseHair1: { setPrice: 5, text: t('hairSet1') },
|
||||
@@ -29,7 +30,7 @@ export default prefill({
|
||||
setPrice: 5, availableFrom: '2021-09-28T08:00-04:00', availableUntil: '2021-10-31T20:00-04:00', text: t('supernaturalSkins'),
|
||||
},
|
||||
splashySkins: {
|
||||
setPrice: 5, availableFrom: '2021-07-13T08:00-04:00', availableUntil: '2021-07-31T20:00-04:00', text: t('splashySkins'),
|
||||
setPrice: 5, availableFrom: '2022-07-05T08:00-05:00', availableUntil: EVENTS.summer2022.end, text: t('splashySkins'),
|
||||
},
|
||||
winterySkins: {
|
||||
setPrice: 5, availableFrom: '2021-12-23T08:00-05:00', availableUntil: '2022-01-31T20:00-05:00', text: t('winterySkins'),
|
||||
|
||||
@@ -396,6 +396,11 @@ const armor = {
|
||||
con: 9,
|
||||
set: 'strawRaincoat',
|
||||
},
|
||||
fancyPirateSuit: {
|
||||
con: 4,
|
||||
int: 4,
|
||||
set: 'fancyPirate',
|
||||
},
|
||||
};
|
||||
|
||||
const body = {
|
||||
@@ -803,6 +808,10 @@ const head = {
|
||||
per: 9,
|
||||
set: 'strawRaincoat',
|
||||
},
|
||||
fancyPirateHat: {
|
||||
per: 8,
|
||||
set: 'fancyPirate',
|
||||
},
|
||||
};
|
||||
|
||||
const shield = {
|
||||
@@ -1086,6 +1095,11 @@ const shield = {
|
||||
int: 6,
|
||||
set: 'musicalInstrumentOne',
|
||||
},
|
||||
treasureMap: {
|
||||
int: 4,
|
||||
str: 4,
|
||||
set: 'fancyPirate',
|
||||
},
|
||||
};
|
||||
|
||||
const headAccessory = {
|
||||
|
||||
@@ -57,6 +57,7 @@ const armor = {
|
||||
202110: { },
|
||||
202112: { },
|
||||
202204: { },
|
||||
202207: { },
|
||||
301404: { },
|
||||
301703: { },
|
||||
301704: { },
|
||||
@@ -118,6 +119,7 @@ const eyewear = {
|
||||
202202: { },
|
||||
'202204A': { mystery: '202204' },
|
||||
'202204B': { mystery: '202204' },
|
||||
202208: { },
|
||||
301404: { },
|
||||
301405: { },
|
||||
301703: { },
|
||||
@@ -190,6 +192,8 @@ const head = {
|
||||
202112: { },
|
||||
202202: { },
|
||||
202206: { },
|
||||
202207: { },
|
||||
202208: { },
|
||||
301404: { },
|
||||
301405: { },
|
||||
301703: { },
|
||||
|
||||
@@ -398,7 +398,7 @@ spells.special = {
|
||||
target: 'user',
|
||||
notes: t('spellSpecialSeafoamNotes'),
|
||||
canOwn () {
|
||||
return moment().isBetween('2021-07-06T08:00-04:00', EVENTS.summer2021.end);
|
||||
return moment().isBetween('2022-07-12T08:00-04:00', EVENTS.summer2022.end);
|
||||
},
|
||||
cast (user, target, req) {
|
||||
if (!user.items.special.seafoam) throw new NotAuthorized(t('spellNotOwned')(req.language));
|
||||
|
||||
@@ -42,6 +42,18 @@ export class BuyQuestWithGemOperation extends AbstractGemItemOperation { // esli
|
||||
this.canUserPurchase(user, item);
|
||||
}
|
||||
|
||||
canUserPurchase (user, item) {
|
||||
if (item && item.prereqQuests) {
|
||||
for (const prereq of item.prereqQuests) {
|
||||
if (!user.achievements.quests[prereq]) {
|
||||
throw new NotAuthorized(this.i18n('mustComplete', { quest: prereq }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super.canUserPurchase(user, item);
|
||||
}
|
||||
|
||||
async executeChanges (user, item, req) {
|
||||
if (
|
||||
!user.items.quests[item.key]
|
||||
|
||||
@@ -46,20 +46,22 @@ export class BuyQuestWithGoldOperation extends AbstractGoldItemOperation { // es
|
||||
throw new NotAuthorized(this.i18n('questNotGoldPurchasable', { key }));
|
||||
}
|
||||
|
||||
this.checkPrerequisites(user, key);
|
||||
|
||||
this.canUserPurchase(user, item);
|
||||
}
|
||||
|
||||
checkPrerequisites (user, questKey) {
|
||||
const item = content.quests[questKey];
|
||||
if (questKey === 'lostMasterclasser1' && !this.userAbleToStartMasterClasser(user)) {
|
||||
canUserPurchase (user, item) {
|
||||
if (this.getItemKey() === 'lostMasterclasser1' && !this.userAbleToStartMasterClasser(user)) {
|
||||
throw new NotAuthorized(this.i18n('questUnlockLostMasterclasser'));
|
||||
}
|
||||
|
||||
if (item && item.previous && !user.achievements.quests[item.previous]) {
|
||||
throw new NotAuthorized(this.i18n('mustComplete', { quest: item.previous }));
|
||||
if (item && item.prereqQuests) {
|
||||
for (const prereq of item.prereqQuests) {
|
||||
if (!user.achievements.quests[prereq]) {
|
||||
throw new NotAuthorized(this.i18n('mustComplete', { quest: prereq }));
|
||||
}
|
||||
}
|
||||
}
|
||||
super.canUserPurchase(user, item);
|
||||
}
|
||||
|
||||
executeChanges (user, item, req) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import moment from 'moment';
|
||||
import nconf from 'nconf';
|
||||
import { authWithHeaders } from '../../middlewares/auth';
|
||||
import { model as Group } from '../../models/group';
|
||||
@@ -22,7 +23,11 @@ import { getMatchesByWordArray } from '../../libs/stringUtils';
|
||||
import bannedSlurs from '../../libs/bannedSlurs';
|
||||
import apiError from '../../libs/apiError';
|
||||
import highlightMentions from '../../libs/highlightMentions';
|
||||
import { getAnalyticsServiceByEnvironment } from '../../libs/analyticsService';
|
||||
|
||||
const analytics = getAnalyticsServiceByEnvironment();
|
||||
|
||||
const ACCOUNT_MIN_CHAT_AGE = Number(nconf.get('ACCOUNT_MIN_CHAT_AGE'));
|
||||
const FLAG_REPORT_EMAILS = nconf.get('FLAG_REPORT_EMAIL').split(',').map(email => ({ email, canSend: true }));
|
||||
|
||||
/**
|
||||
@@ -188,6 +193,17 @@ api.postChat = {
|
||||
throw new NotAuthorized(res.t('messageGroupChatSpam'));
|
||||
}
|
||||
|
||||
// Check if account is newer than the minimum age for chat participation
|
||||
if (moment().diff(user.auth.timestamps.created, 'minutes') < ACCOUNT_MIN_CHAT_AGE) {
|
||||
analytics.track('chat age error', {
|
||||
uuid: user._id,
|
||||
hitType: 'event',
|
||||
category: 'behavior',
|
||||
headers: req.headers,
|
||||
});
|
||||
throw new BadRequest(res.t('chatTemporarilyUnavailable'));
|
||||
}
|
||||
|
||||
const sanitizedMessageText = sanitizeMessageText(req.body.message);
|
||||
const [message, mentions, mentionedMembers] = await highlightMentions(sanitizedMessageText);
|
||||
let client = req.headers['x-client'] || '3rd Party';
|
||||
|
||||
@@ -267,7 +267,11 @@ api.updateHero = {
|
||||
const hero = await User.findById(heroId).exec();
|
||||
if (!hero) throw new NotFound(res.t('userWithIDNotFound', { userId: heroId }));
|
||||
|
||||
if (updateData.balance) hero.balance = updateData.balance;
|
||||
if (updateData.balance) {
|
||||
await hero.updateBalance(updateData.balance - hero.balance, 'admin_update_balance', '', 'Given by Habitica staff');
|
||||
|
||||
hero.balance = updateData.balance;
|
||||
}
|
||||
|
||||
// give them gems if they got an higher level
|
||||
// tier = level in this context
|
||||
@@ -323,7 +327,9 @@ api.updateHero = {
|
||||
}
|
||||
}
|
||||
|
||||
if (updateData.changeApiToken) hero.apiToken = common.uuid();
|
||||
if (updateData.changeApiToken) {
|
||||
hero.apiToken = common.uuid();
|
||||
}
|
||||
|
||||
const savedHero = await hero.save();
|
||||
const heroJSON = savedHero.toJSON();
|
||||
|
||||
@@ -714,8 +714,8 @@ api.transferGems = {
|
||||
throw new NotAuthorized(res.t('badAmountOfGemsToSend'));
|
||||
}
|
||||
|
||||
await receiver.updateBalance(amount, 'gift_receive', sender._id, sender.profile.name);
|
||||
await sender.updateBalance(-amount, 'gift_send', sender._id, receiver.profile.name);
|
||||
await receiver.updateBalance(amount, 'gift_receive', sender._id, sender.auth.local.username);
|
||||
await sender.updateBalance(-amount, 'gift_send', sender._id, receiver.auth.local.username);
|
||||
// @TODO necessary? Also saved when sending the inbox message
|
||||
const promises = [receiver.save(), sender.save()];
|
||||
await Promise.all(promises);
|
||||
|
||||
@@ -64,9 +64,15 @@ api.purchaseHistory = {
|
||||
req.checkParams('memberId', res.t('memberIdRequired')).notEmpty().isUUID();
|
||||
const validationErrors = req.validationErrors();
|
||||
if (validationErrors) throw validationErrors;
|
||||
const transactions = await Transaction
|
||||
let transactions = await Transaction
|
||||
.find({ userId: req.params.memberId })
|
||||
.sort({ createdAt: -1 });
|
||||
.sort({ createdAt: -1 })
|
||||
.exec();
|
||||
|
||||
if (!res.locals.user.hasPermission('userSupport')) {
|
||||
transactions = transactions.filter(t => t.transactionType !== 'create_bank_challenge');
|
||||
}
|
||||
|
||||
res.respond(200, transactions);
|
||||
},
|
||||
};
|
||||
|
||||
@@ -35,7 +35,7 @@ export async function socialEmailToLocal (user) {
|
||||
).exec();
|
||||
if (!conflictingUser) return socialEmail;
|
||||
}
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export async function loginSocial (req, res) { // eslint-disable-line import/prefer-default-export
|
||||
|
||||
@@ -103,6 +103,8 @@ const bannedWords = [
|
||||
'bullshitting',
|
||||
'shiz',
|
||||
'shit',
|
||||
'shite',
|
||||
'shits',
|
||||
'shitty',
|
||||
'shitting',
|
||||
'shithole',
|
||||
|
||||
@@ -74,14 +74,16 @@ export async function createChallenge (user, req, res) {
|
||||
if (groupBalance >= prizeCost) {
|
||||
// Group pays for all of prize
|
||||
group.balance -= prizeCost;
|
||||
|
||||
await user.updateBalance(0, 'create_bank_challenge', challenge._id, challenge.name);
|
||||
} else if (groupBalance > 0) {
|
||||
// User pays remainder of prize cost after group
|
||||
const remainder = prizeCost - group.balance;
|
||||
group.balance = 0;
|
||||
await user.updateBalance(-remainder, 'create_challenge', challenge._id, challenge.text);
|
||||
await user.updateBalance(-remainder, 'create_challenge', challenge._id, challenge.name);
|
||||
} else {
|
||||
// User pays for all of prize
|
||||
await user.updateBalance(-prizeCost, 'create_challenge', challenge._id, challenge.text);
|
||||
await user.updateBalance(-prizeCost, 'create_challenge', challenge._id, challenge.name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,8 @@ schema.methods.updateHourglasses = async function updateHourglasses (userId,
|
||||
amount,
|
||||
reference,
|
||||
referenceText,
|
||||
|
||||
currentAmount: this.consecutive.trinkets,
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import baseModel from '../libs/baseModel';
|
||||
const { Schema } = mongoose;
|
||||
|
||||
export const currencies = ['gems', 'hourglasses'];
|
||||
export const transactionTypes = ['buy_money', 'buy_gold', 'contribution', 'spend', 'gift_send', 'gift_receive', 'debug', 'create_challenge', 'create_guild', 'change_class', 'rebirth', 'release_pets', 'release_mounts', 'reroll', 'contribution', 'subscription_perks'];
|
||||
export const transactionTypes = ['buy_money', 'buy_gold', 'spend', 'gift_send', 'gift_receive', 'debug', 'create_challenge', 'create_bank_challenge', 'create_guild', 'change_class', 'rebirth', 'release_pets', 'release_mounts', 'reroll', 'contribution', 'subscription_perks', 'admin_update_balance'];
|
||||
|
||||
export const schema = new Schema({
|
||||
currency: { $type: String, enum: currencies, required: true },
|
||||
@@ -13,6 +13,7 @@ export const schema = new Schema({
|
||||
reference: { $type: String },
|
||||
referenceText: { $type: String },
|
||||
amount: { $type: Number, required: true },
|
||||
currentAmount: { $type: Number },
|
||||
userId: {
|
||||
$type: String, ref: 'User', required: true, validate: [v => validator.isUUID(v), 'Invalid uuid for Transaction.'],
|
||||
},
|
||||
@@ -23,7 +24,17 @@ export const schema = new Schema({
|
||||
});
|
||||
|
||||
schema.plugin(baseModel, {
|
||||
noSet: ['id', '_id', 'userId', 'currency', 'transactionType', 'reference', 'referenceText', 'amount'], // Nothing can be set from the client
|
||||
noSet: [
|
||||
'id',
|
||||
'_id',
|
||||
'userId',
|
||||
'currency',
|
||||
'transactionType',
|
||||
'reference',
|
||||
'referenceText',
|
||||
'amount',
|
||||
'currentAmount',
|
||||
], // Nothing can be set from the client
|
||||
timestamps: true,
|
||||
_id: false, // using custom _id
|
||||
});
|
||||
|
||||
@@ -559,5 +559,6 @@ schema.methods.updateBalance = async function updateBalance (amount,
|
||||
amount,
|
||||
reference,
|
||||
referenceText,
|
||||
currentAmount: this.balance,
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user