Compare commits
145 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8c4d1a67ac | |||
| e58fbcc34c | |||
| 1a66a680dc | |||
| fc08b753cd | |||
| 7a73f5bb83 | |||
| 6ce1f6f32e | |||
| 50278db1d6 | |||
| fe636b9bd2 | |||
| 7835fe1deb | |||
| 8fb0d0899d | |||
| abb8dc4dc1 | |||
| 910a76db68 | |||
| 2f792d51f8 | |||
| 6cc925b535 | |||
| 87d86ee632 | |||
| b387d77128 | |||
| e644ae83fd | |||
| ae21680a5f | |||
| c1767eca1b | |||
| d20cd1bbf1 | |||
| 3e45f5af41 | |||
| 23cc2b9d21 | |||
| 58c4fcd506 | |||
| 2878abc130 | |||
| a8cb6e3409 | |||
| 2caa540006 | |||
| a2261e3591 | |||
| 90d498ff96 | |||
| 928327e02a | |||
| f454700722 | |||
| 83bce24e1f | |||
| e7979a99e6 | |||
| 5c648af2ea | |||
| 2ad4bee816 | |||
| e0291cf432 | |||
| bac9121153 | |||
| d178928c45 | |||
| 9a6aa5f443 | |||
| e277a088ee | |||
| e083df64e4 | |||
| dae37c17d6 | |||
| 1d81916674 | |||
| 2a225c2376 | |||
| bd9d9d31c3 | |||
| f1b5ce9c66 | |||
| c08b25101b | |||
| 9fd0e27c66 | |||
| 994082a1d8 | |||
| 0e6e7adb06 | |||
| 8486b9631f | |||
| 3f04c8abf5 | |||
| 89e1c69728 | |||
| 5e935230a4 | |||
| 9ad50be6ca | |||
| 1ff3f3d4e7 | |||
| 0b35aefdc9 | |||
| 0d374d817c | |||
| 034058301d | |||
| ae2d50c5b8 | |||
| fff16a86a5 | |||
| c7309ae179 | |||
| ef42fba049 | |||
| d75f926136 | |||
| 78612a91dd | |||
| 8bcd93075b | |||
| f318afb8cf | |||
| b954379f38 | |||
| e5c060a80b | |||
| 6668aae89b | |||
| 9b62804a5c | |||
| d21e29462c | |||
| 6bccd2a866 | |||
| caea222330 | |||
| 8ecbdc1448 | |||
| ee20b1eea8 | |||
| ff62c6eea0 | |||
| 57cd4d44cd | |||
| e989503cfa | |||
| 431cec7634 | |||
| 2a367ab3a7 | |||
| bc91dd81e9 | |||
| 201085651b | |||
| 660928323e | |||
| 298a79b58d | |||
| 77f3bb53de | |||
| 17d8a7b706 | |||
| 1d8a5b1952 | |||
| f548103f4c | |||
| 2595ccb2b4 | |||
| ceb4288b17 | |||
| 3ebd37f7cb | |||
| ff3df55639 | |||
| 080c4b3e20 | |||
| e939799800 | |||
| f137342d88 | |||
| 94db493974 | |||
| ee5c761680 | |||
| 0cbd6fb4d7 | |||
| 0ca3c1f94d | |||
| 2f699e24d7 | |||
| faa0611ab2 | |||
| c66d2cb469 | |||
| 61606cb69d | |||
| 3d99a64e96 | |||
| 76f9204417 | |||
| 73ecdced01 | |||
| 1c17b415f0 | |||
| b912a83f22 | |||
| fb3a9740bd | |||
| 817c943860 | |||
| 0aba448c48 | |||
| 6b5173ecbf | |||
| 53d8d2fc6a | |||
| 52a7112591 | |||
| fd13771088 | |||
| c9d725ec20 | |||
| 3203bffeaa | |||
| 3f47cdd9a2 | |||
| 8b15d94ae1 | |||
| 8f2435c37c | |||
| 302bc899d7 | |||
| 8048cf9a97 | |||
| 20548daccf | |||
| 2c250bfcd9 | |||
| 75e3f15352 | |||
| 5670be26c7 | |||
| 9fc03cb91a | |||
| 7e80406181 | |||
| 60a6f6f2f6 | |||
| 92d68e5c6e | |||
| 6e7d8d93fe | |||
| bc861133e1 | |||
| 31ef21f25c | |||
| 97e1465899 | |||
| 7cb0f5145d | |||
| 5b6217a0bf | |||
| 09e4c88606 | |||
| 13bae96708 | |||
| 6241001eef | |||
| dc5722d0de | |||
| e3b2443029 | |||
| ca5927fe73 | |||
| 5a0eed7eae | |||
| 532881e679 | |||
| 27d763a46c |
@@ -1,6 +1,6 @@
|
||||
/* eslint-disable no-console */
|
||||
const MIGRATION_NAME = 'mystery_items_201902';
|
||||
const MYSTERY_ITEMS = ['eyewear_mystery_201902', 'shield_mystery_201902'];
|
||||
const MIGRATION_NAME = 'mystery_items_201903';
|
||||
const MYSTERY_ITEMS = ['armor_mystery_201903', 'head_mystery_201903'];
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
import { model as UserNotification } from '../../website/server/models/userNotification';
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/* eslint-disable no-console */
|
||||
const MIGRATION_NAME = '20190314_pi_day';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
async function updateUser (user) {
|
||||
count++;
|
||||
|
||||
const inc = {
|
||||
'items.food.Pie_Skeleton': 1,
|
||||
'items.food.Pie_Base': 1,
|
||||
'items.food.Pie_CottonCandyBlue': 1,
|
||||
'items.food.Pie_CottonCandyPink': 1,
|
||||
'items.food.Pie_Shade': 1,
|
||||
'items.food.Pie_White': 1,
|
||||
'items.food.Pie_Golden': 1,
|
||||
'items.food.Pie_Zombie': 1,
|
||||
'items.food.Pie_Desert': 1,
|
||||
'items.food.Pie_Red': 1,
|
||||
};
|
||||
const set = {};
|
||||
|
||||
set.migration = MIGRATION_NAME;
|
||||
|
||||
set['items.gear.owned.head_special_piDay'] = false;
|
||||
set['items.gear.owned.shield_special_piDay'] = false;
|
||||
const push = [
|
||||
{type: 'marketGear', path: 'gear.flat.head_special_piDay', _id: uuid()},
|
||||
{type: 'marketGear', path: 'gear.flat.shield_special_piDay', _id: uuid()},
|
||||
];
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
|
||||
return await User.update({_id: user._id}, {$inc: inc, $set: set, $push: {pinnedItems: {$each: push}}}).exec();
|
||||
}
|
||||
|
||||
module.exports = async function processUsers () {
|
||||
let query = {
|
||||
migration: {$ne: MIGRATION_NAME},
|
||||
'auth.timestamps.loggedin': {$gt: new Date('2019-02-15')},
|
||||
};
|
||||
|
||||
const fields = {
|
||||
_id: 1,
|
||||
items: 1,
|
||||
};
|
||||
|
||||
while (true) { // eslint-disable-line no-constant-condition
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({_id: 1})
|
||||
.select(fields)
|
||||
.lean()
|
||||
.exec();
|
||||
|
||||
if (users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
break;
|
||||
} else {
|
||||
query._id = {
|
||||
$gt: users[users.length - 1],
|
||||
};
|
||||
}
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"version": "4.86.0",
|
||||
"version": "4.90.1",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
|
||||
"version": "4.86.0",
|
||||
"version": "4.90.1",
|
||||
"main": "./website/server/index.js",
|
||||
"dependencies": {
|
||||
"@google-cloud/trace-agent": "^3.5.2",
|
||||
|
||||
@@ -32,6 +32,7 @@ describe('slack', () => {
|
||||
},
|
||||
message: {
|
||||
id: 'chat-id',
|
||||
username: 'author',
|
||||
user: 'Author',
|
||||
uuid: 'author-id',
|
||||
text: 'some text',
|
||||
@@ -50,11 +51,11 @@ describe('slack', () => {
|
||||
|
||||
expect(IncomingWebhook.prototype.send).to.be.calledOnce;
|
||||
expect(IncomingWebhook.prototype.send).to.be.calledWith({
|
||||
text: 'flagger (flagger-id; language: flagger-lang) flagged a message',
|
||||
text: 'flagger (flagger-id; language: flagger-lang) flagged a group message',
|
||||
attachments: [{
|
||||
fallback: 'Flag Message',
|
||||
color: 'danger',
|
||||
author_name: `Author - author@example.com - author-id\n${timestamp}`,
|
||||
author_name: `@author Author (author@example.com; author-id)\n${timestamp}`,
|
||||
title: 'Flag in Some group - (private guild)',
|
||||
title_link: undefined,
|
||||
text: 'some text',
|
||||
|
||||
@@ -63,11 +63,11 @@ describe('POST /chat/:chatId/flag', () => {
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
expect(IncomingWebhook.prototype.send).to.be.calledWith({
|
||||
text: `${user.profile.name} (${user.id}; language: en) flagged a message`,
|
||||
text: `${user.profile.name} (${user.id}; language: en) flagged a group message`,
|
||||
attachments: [{
|
||||
fallback: 'Flag Message',
|
||||
color: 'danger',
|
||||
author_name: `${anotherUser.profile.name} - ${anotherUser.auth.local.email} - ${anotherUser._id}\n${timestamp}`,
|
||||
author_name: `@${anotherUser.auth.local.username} ${anotherUser.profile.name} (${anotherUser.auth.local.email}; ${anotherUser._id})\n${timestamp}`,
|
||||
title: 'Flag in Test Guild',
|
||||
title_link: `${BASE_URL}/groups/guild/${group._id}`,
|
||||
text: TEST_MESSAGE,
|
||||
@@ -98,11 +98,11 @@ describe('POST /chat/:chatId/flag', () => {
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
expect(IncomingWebhook.prototype.send).to.be.calledWith({
|
||||
text: `${newUser.profile.name} (${newUser.id}; language: en) flagged a message`,
|
||||
text: `${newUser.profile.name} (${newUser.id}; language: en) flagged a group message`,
|
||||
attachments: [{
|
||||
fallback: 'Flag Message',
|
||||
color: 'danger',
|
||||
author_name: `${newUser.profile.name} - ${newUser.auth.local.email} - ${newUser._id}\n${timestamp}`,
|
||||
author_name: `@${newUser.auth.local.username} ${newUser.profile.name} (${newUser.auth.local.email}; ${newUser._id})\n${timestamp}`,
|
||||
title: 'Flag in Test Guild',
|
||||
title_link: `${BASE_URL}/groups/guild/${group._id}`,
|
||||
text: TEST_MESSAGE,
|
||||
|
||||
@@ -257,7 +257,7 @@ describe('POST /chat', () => {
|
||||
attachments: [{
|
||||
fallback: 'Slur Message',
|
||||
color: 'danger',
|
||||
author_name: `${user.profile.name} - ${user.auth.local.email} - ${user._id}`,
|
||||
author_name: `@${user.auth.local.username} ${user.profile.name} (${user.auth.local.email}; ${user._id})`,
|
||||
title: 'Slur in Test Guild',
|
||||
title_link: `${BASE_URL}/groups/guild/${groupWithChat.id}`,
|
||||
text: testSlurMessage,
|
||||
@@ -310,7 +310,7 @@ describe('POST /chat', () => {
|
||||
attachments: [{
|
||||
fallback: 'Slur Message',
|
||||
color: 'danger',
|
||||
author_name: `${members[0].profile.name} - ${members[0].auth.local.email} - ${members[0]._id}`,
|
||||
author_name: `@${members[0].auth.local.username} ${members[0].profile.name} (${members[0].auth.local.email}; ${members[0]._id})`,
|
||||
title: 'Slur in Party - (private party)',
|
||||
title_link: undefined,
|
||||
text: testSlurMessage,
|
||||
|
||||
@@ -67,4 +67,10 @@ describe('GET /heroes/:heroId', () => {
|
||||
expect(heroRes.auth.local).not.to.have.keys(['salt', 'hashed_password']);
|
||||
expect(heroRes.profile).to.have.all.keys(['name']);
|
||||
});
|
||||
|
||||
it('returns correct hero using search with difference case', async () => {
|
||||
await generateUser({}, { username: 'TestUpperCaseName123' });
|
||||
let heroRes = await user.get('/hall/heroes/TestuPPerCasEName123');
|
||||
expect(heroRes.auth.local.username).to.equal('TestUpperCaseName123');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -110,4 +110,22 @@ describe('POST /user/auth/local/login', () => {
|
||||
let isValidPassword = await bcryptCompare(textPassword, user.auth.local.hashed_password);
|
||||
expect(isValidPassword).to.equal(true);
|
||||
});
|
||||
|
||||
it('user uses social authentication and has no password', async () => {
|
||||
await user.unset({
|
||||
'auth.local.hashed_password': 1,
|
||||
});
|
||||
|
||||
await user.sync();
|
||||
expect(user.auth.local.hashed_password).to.be.undefined;
|
||||
|
||||
await expect(api.post(endpoint, {
|
||||
username: user.auth.local.username,
|
||||
password: 'any-password',
|
||||
})).to.eventually.be.rejected.and.eql({
|
||||
code: 401,
|
||||
error: 'NotAuthorized',
|
||||
message: t('invalidLoginCredentialsLong'),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import {
|
||||
generateUser,
|
||||
translate as t,
|
||||
} from '../../../helpers/api-integration/v4';
|
||||
|
||||
describe('POST /members/flag-private-message/:messageId', () => {
|
||||
let userToSendMessage;
|
||||
let messageToSend = 'Test Private Message';
|
||||
|
||||
beforeEach(async () => {
|
||||
userToSendMessage = await generateUser();
|
||||
});
|
||||
|
||||
it('Allows players to flag their own private message', async () => {
|
||||
let receiver = await generateUser();
|
||||
|
||||
await userToSendMessage.post('/members/send-private-message', {
|
||||
message: messageToSend,
|
||||
toUserId: receiver._id,
|
||||
});
|
||||
|
||||
let senderMessages = await userToSendMessage.get('/inbox/messages');
|
||||
|
||||
let sendersMessageInSendersInbox = _.find(senderMessages, (message) => {
|
||||
return message.uuid === receiver._id && message.text === messageToSend;
|
||||
});
|
||||
|
||||
expect(sendersMessageInSendersInbox).to.exist;
|
||||
await expect(userToSendMessage.post(`/members/flag-private-message/${sendersMessageInSendersInbox.id}`)).to.eventually.be.ok;
|
||||
});
|
||||
|
||||
it('Flags a private message', async () => {
|
||||
let receiver = await generateUser();
|
||||
|
||||
await userToSendMessage.post('/members/send-private-message', {
|
||||
message: messageToSend,
|
||||
toUserId: receiver._id,
|
||||
});
|
||||
|
||||
let receiversMessages = await receiver.get('/inbox/messages');
|
||||
|
||||
let sendersMessageInReceiversInbox = _.find(receiversMessages, (message) => {
|
||||
return message.uuid === userToSendMessage._id && message.text === messageToSend;
|
||||
});
|
||||
|
||||
expect(sendersMessageInReceiversInbox).to.exist;
|
||||
await expect(receiver.post(`/members/flag-private-message/${sendersMessageInReceiversInbox.id}`)).to.eventually.be.ok;
|
||||
});
|
||||
|
||||
it('Returns an error when user tries to flag a private message that is already flagged', async () => {
|
||||
let receiver = await generateUser();
|
||||
|
||||
await userToSendMessage.post('/members/send-private-message', {
|
||||
message: messageToSend,
|
||||
toUserId: receiver._id,
|
||||
});
|
||||
|
||||
let receiversMessages = await receiver.get('/inbox/messages');
|
||||
|
||||
let sendersMessageInReceiversInbox = _.find(receiversMessages, (message) => {
|
||||
return message.uuid === userToSendMessage._id && message.text === messageToSend;
|
||||
});
|
||||
|
||||
expect(sendersMessageInReceiversInbox).to.exist;
|
||||
await expect(receiver.post(`/members/flag-private-message/${sendersMessageInReceiversInbox.id}`)).to.eventually.be.ok;
|
||||
|
||||
await expect(receiver.post(`/members/flag-private-message/${sendersMessageInReceiversInbox.id}`))
|
||||
.to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('messageGroupChatFlagAlreadyReported'),
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -4,6 +4,7 @@ import { requester } from './requester';
|
||||
import {
|
||||
getDocument as getDocumentFromMongo,
|
||||
updateDocument as updateDocumentInMongo,
|
||||
unsetDocument as unsetDocumentInMongo,
|
||||
} from '../mongo';
|
||||
import {
|
||||
assign,
|
||||
@@ -29,6 +30,18 @@ class ApiObject {
|
||||
return this;
|
||||
}
|
||||
|
||||
async unset (options) {
|
||||
if (isEmpty(options)) {
|
||||
return;
|
||||
}
|
||||
|
||||
await unsetDocumentInMongo(this._docType, this, options);
|
||||
|
||||
_updateLocalParameters((this, options));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
async sync () {
|
||||
let updatedDoc = await getDocumentFromMongo(this._docType, this);
|
||||
|
||||
|
||||
@@ -13,10 +13,16 @@ import * as Tasks from '../../../../website/server/models/task';
|
||||
// parameter, such as the number of wolf eggs the user has,
|
||||
// , you can do so by passing in the full path as a string:
|
||||
// { 'items.eggs.Wolf': 10 }
|
||||
export async function generateUser (update = {}) {
|
||||
let username = (Date.now() + generateUUID()).substring(0, 20);
|
||||
let password = 'password';
|
||||
let email = `${username}@example.com`;
|
||||
//
|
||||
// To manually set a username, email or password pass it in as
|
||||
// an object for the second parameter. Only overrides need to be
|
||||
// added. Items that don't exist will be autogenerated.
|
||||
// Example: generateUser({}, { username: 'TestName' }) adds user
|
||||
// with the 'TestName' username.
|
||||
export async function generateUser (update = {}, overrides = {}) {
|
||||
let username = overrides.username || (Date.now() + generateUUID()).substring(0, 20);
|
||||
let password = overrides.password || 'password';
|
||||
let email = overrides.email || `${username}@example.com`;
|
||||
|
||||
let user = await requester().post('/user/auth/local/register', {
|
||||
username,
|
||||
|
||||
@@ -98,6 +98,19 @@ export async function updateDocument (collectionName, doc, update) {
|
||||
});
|
||||
}
|
||||
|
||||
// Unset a property in the database.
|
||||
// Useful for testing.
|
||||
export async function unsetDocument (collectionName, doc, update) {
|
||||
let collection = mongoose.connection.db.collection(collectionName);
|
||||
|
||||
return new Promise((resolve) => {
|
||||
collection.updateOne({ _id: doc._id }, { $unset: update }, (updateErr) => {
|
||||
if (updateErr) throw new Error(`Error updating ${collectionName}: ${updateErr}`);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export async function getDocument (collectionName, doc) {
|
||||
let collection = mongoose.connection.db.collection(collectionName);
|
||||
|
||||
|
||||
@@ -1,42 +1,72 @@
|
||||
.promo_armoire_backgrounds_201903 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px -220px;
|
||||
background-position: -719px -767px;
|
||||
width: 423px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_beffymaroo_wondercon {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px 0px;
|
||||
width: 718px;
|
||||
height: 932px;
|
||||
}
|
||||
.promo_celestial_rainbow_potions {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px -933px;
|
||||
width: 423px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_classes_spring2019 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -719px -604px;
|
||||
width: 432px;
|
||||
height: 162px;
|
||||
}
|
||||
.promo_egg_hunt {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -424px -933px;
|
||||
width: 354px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_mystery_201902 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -424px -220px;
|
||||
background-position: -1160px -196px;
|
||||
width: 240px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_mythical_marvels_bundle {
|
||||
.promo_mystery_201903 {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px -368px;
|
||||
width: 423px;
|
||||
background-position: -779px -933px;
|
||||
width: 351px;
|
||||
height: 147px;
|
||||
}
|
||||
.promo_seasonalshop_spring {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -1160px -344px;
|
||||
width: 162px;
|
||||
height: 138px;
|
||||
}
|
||||
.promo_take_this {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -424px -368px;
|
||||
background-position: -1160px -483px;
|
||||
width: 96px;
|
||||
height: 69px;
|
||||
}
|
||||
.promo_valentines_potions {
|
||||
.scene_dailies {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px -516px;
|
||||
width: 420px;
|
||||
height: 147px;
|
||||
background-position: -719px -327px;
|
||||
width: 327px;
|
||||
height: 276px;
|
||||
}
|
||||
.scene_achievement {
|
||||
.scene_tavern {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: -397px 0px;
|
||||
width: 339px;
|
||||
height: 210px;
|
||||
background-position: -719px 0px;
|
||||
width: 440px;
|
||||
height: 326px;
|
||||
}
|
||||
.scene_cooking {
|
||||
.scene_todos {
|
||||
background-image: url('~assets/images/sprites/spritesmith-largeSprites-0.png');
|
||||
background-position: 0px 0px;
|
||||
width: 396px;
|
||||
height: 219px;
|
||||
background-position: -1160px 0px;
|
||||
width: 240px;
|
||||
height: 195px;
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 968 KiB |
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 112 KiB |
|
Before Width: | Height: | Size: 354 KiB After Width: | Height: | Size: 344 KiB |
|
Before Width: | Height: | Size: 307 KiB After Width: | Height: | Size: 314 KiB |
|
Before Width: | Height: | Size: 159 KiB After Width: | Height: | Size: 149 KiB |
|
Before Width: | Height: | Size: 143 KiB After Width: | Height: | Size: 152 KiB |
|
Before Width: | Height: | Size: 136 KiB After Width: | Height: | Size: 140 KiB |
|
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 141 KiB |
|
Before Width: | Height: | Size: 144 KiB After Width: | Height: | Size: 158 KiB |
|
Before Width: | Height: | Size: 149 KiB After Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 153 KiB After Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 156 KiB |
|
Before Width: | Height: | Size: 183 KiB After Width: | Height: | Size: 164 KiB |
|
Before Width: | Height: | Size: 159 KiB After Width: | Height: | Size: 177 KiB |
|
Before Width: | Height: | Size: 165 KiB After Width: | Height: | Size: 164 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 144 KiB After Width: | Height: | Size: 147 KiB |
|
Before Width: | Height: | Size: 115 KiB After Width: | Height: | Size: 115 KiB |
@@ -0,0 +1,26 @@
|
||||
.vdp-datepicker .vdp-datepicker__calendar {
|
||||
|
||||
.cell:not(.blank):not(.disabled).day:hover {
|
||||
border-radius: 2px;
|
||||
border: 1px solid $purple-400;
|
||||
}
|
||||
|
||||
.cell.selected,
|
||||
.cell.selected.highlighted,
|
||||
.cell.selected:hover {
|
||||
color: $white;
|
||||
background: $purple-300;
|
||||
}
|
||||
|
||||
.cell.highlighted {
|
||||
background: rgba($purple-400, 0.24);
|
||||
color: $purple-200;
|
||||
}
|
||||
|
||||
.cell.highlighted,
|
||||
.cell.selected {
|
||||
border-radius: 2px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -159,7 +159,7 @@ $bg-disabled-control: #34303a;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background-image: url(~client/assets/svg/for-css/checkbox-white.svg);
|
||||
background-size: 75% 75%;
|
||||
background-size: 13px 10px;
|
||||
}
|
||||
|
||||
&:active~.custom-control-label::before {
|
||||
|
||||
@@ -36,3 +36,5 @@
|
||||
@import './animals';
|
||||
@import './iconalert';
|
||||
@import './tiers';
|
||||
@import './payments';
|
||||
@import './datepicker.scss';
|
||||
@@ -0,0 +1,44 @@
|
||||
.payments-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 296px;
|
||||
justify-content: center;
|
||||
|
||||
&.payments-disabled {
|
||||
opacity: 0.64;
|
||||
|
||||
.btn, .btn:hover, .btn:active {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.payment-item > *{
|
||||
cursor: default !important;
|
||||
}
|
||||
}
|
||||
|
||||
.payment-item {
|
||||
margin-bottom: 12px;
|
||||
display: flex;
|
||||
|
||||
&.payment-button {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
.credit-card-icon {
|
||||
width: 21.3px;
|
||||
height: 16px;
|
||||
margin-right: 8.7px;
|
||||
}
|
||||
|
||||
&.paypal-checkout {
|
||||
background: #009cde;
|
||||
|
||||
img {
|
||||
width: 157px;
|
||||
height: 21px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
// possible values are: normal, fall, habitoween, thanksgiving, winter, nye, birthday, valentines, spring, summer
|
||||
// more to be added on future seasons
|
||||
|
||||
$npc_market_flavor: 'normal';
|
||||
$npc_quests_flavor: 'normal';
|
||||
$npc_seasonal_flavor: 'normal';
|
||||
$npc_timetravelers_flavor: 'normal';
|
||||
$npc_tavern_flavor: 'normal';
|
||||
$npc_market_flavor: 'spring';
|
||||
$npc_quests_flavor: 'spring';
|
||||
$npc_seasonal_flavor: 'spring';
|
||||
$npc_timetravelers_flavor: 'spring';
|
||||
$npc_tavern_flavor: 'spring';
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="16" viewBox="0 0 22 16">
|
||||
<path fill="#FFF" fill-rule="nonzero" d="M0 13.872V5.333h21.333v8.539c0 1.176-.747 2.128-1.67 2.128H1.67C.747 16 0 15.047 0 13.872zM19.664 0c.922 0 1.67.918 1.67 2.053v.614H0v-.614C0 .918.747 0 1.67 0h17.994z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 307 B |
@@ -1,3 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<path fill="#E1E0E3" fill-rule="evenodd" d="M10.667 10.667L16 8l-5.333-2.667L8 0 5.333 5.333 0 8l5.333 2.667L8 16z"/>
|
||||
<path class="star-empty" fill="#E1E0E3" fill-rule="evenodd" d="M10.667 10.667L16 8l-5.333-2.667L8 0 5.333 5.333 0 8l5.333 2.667L8 16z"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 213 B After Width: | Height: | Size: 232 B |
@@ -1,6 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path fill="#E1E0E3" d="M10.667 10.667L16 8l-5.333-2.667L8 0 5.333 5.333 0 8l5.333 2.667L8 16z"/>
|
||||
<path fill="#FFB445" d="M8 0L5.333 5.333 0 8l5.333 2.667L8 16z"/>
|
||||
<path class="star-empty" fill="#E1E0E3" d="M10.667 10.667L16 8l-5.333-2.667L8 0 5.333 5.333 0 8l5.333 2.667L8 16z"/>
|
||||
<path class="star" fill="#FFB445" d="M8 0L5.333 5.333 0 8l5.333 2.667L8 16z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 320 B After Width: | Height: | Size: 352 B |
@@ -1,3 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<path fill="#FFB445" fill-rule="evenodd" d="M10.667 10.667L16 8l-5.333-2.667L8 0 5.333 5.333 0 8l5.333 2.667L8 16z"/>
|
||||
<path class="star" fill="#FFB445" fill-rule="evenodd" d="M10.667 10.667L16 8l-5.333-2.667L8 0 5.333 5.333 0 8l5.333 2.667L8 16z"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 213 B After Width: | Height: | Size: 226 B |
@@ -164,30 +164,30 @@ export default {
|
||||
classGear (heroClass) {
|
||||
if (heroClass === 'rogue') {
|
||||
return {
|
||||
armor: 'armor_rogue_5',
|
||||
head: 'head_rogue_5',
|
||||
shield: 'shield_rogue_6',
|
||||
weapon: 'weapon_rogue_6',
|
||||
armor: 'armor_special_spring2019Rogue',
|
||||
head: 'head_special_spring2019Rogue',
|
||||
shield: 'shield_special_spring2019Rogue',
|
||||
weapon: 'weapon_special_spring2019Rogue',
|
||||
};
|
||||
} else if (heroClass === 'wizard') {
|
||||
return {
|
||||
armor: 'armor_wizard_5',
|
||||
head: 'head_wizard_5',
|
||||
weapon: 'weapon_wizard_6',
|
||||
armor: 'armor_special_spring2019Mage',
|
||||
head: 'head_special_spring2019Mage',
|
||||
weapon: 'weapon_special_spring2019Mage',
|
||||
};
|
||||
} else if (heroClass === 'healer') {
|
||||
return {
|
||||
armor: 'armor_healer_5',
|
||||
head: 'head_healer_5',
|
||||
shield: 'shield_healer_5',
|
||||
weapon: 'weapon_healer_6',
|
||||
armor: 'armor_special_spring2019Healer',
|
||||
head: 'head_special_spring2019Healer',
|
||||
shield: 'shield_special_spring2019Healer',
|
||||
weapon: 'weapon_special_spring2019Healer',
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
armor: 'armor_warrior_5',
|
||||
head: 'head_warrior_5',
|
||||
shield: 'shield_warrior_5',
|
||||
weapon: 'weapon_warrior_6',
|
||||
armor: 'armor_special_spring2019Warrior',
|
||||
head: 'head_special_spring2019Warrior',
|
||||
shield: 'shield_special_spring2019Warrior',
|
||||
weapon: 'weapon_special_spring2019Warrior',
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
@@ -43,6 +43,8 @@
|
||||
li(v-html='$t("communityForum")')
|
||||
li
|
||||
a(href='https://www.facebook.com/Habitica', target='_blank') {{ $t('communityFacebook') }}
|
||||
li
|
||||
a(href='https://www.instagram.com/habitica', target='_blank') {{ $t('communityInstagram') }}
|
||||
li
|
||||
a(href='https://www.reddit.com/r/habitrpg/', target='_blank') {{ $t('communityReddit') }}
|
||||
.col-12.col-md-6
|
||||
@@ -56,23 +58,22 @@
|
||||
a(:href="getDataDisplayToolUrl", target='_blank') {{ $t('dataDisplayTool') }}
|
||||
li
|
||||
a(href='http://habitica.fandom.com/wiki/Guidance_for_Blacksmiths', target='_blank') {{ $t('guidanceForBlacksmiths') }}
|
||||
li
|
||||
a(href='http://devs.habitica.com/', target='_blank') {{ $t('devBlog') }}
|
||||
.col-6.social
|
||||
h3 {{ $t('footerSocial') }}
|
||||
a.social-circle(href='https://twitter.com/habitica', target='_blank')
|
||||
.social-icon.svg-icon(v-html='icons.twitter')
|
||||
// TODO: Not ready yet. a.social-circle(href='https://www.instagram.com/habitica/', target='_blank')
|
||||
.social-icon.svg-icon.instagram(v-html='icons.instagram')
|
||||
a.social-circle(href='https://www.facebook.com/Habitica', target='_blank')
|
||||
.social-icon.facebook.svg-icon(v-html='icons.facebook')
|
||||
.icons
|
||||
a.social-circle(href='https://twitter.com/habitica', target='_blank')
|
||||
.social-icon.svg-icon(v-html='icons.twitter')
|
||||
a.social-circle(href='https://www.instagram.com/habitica/', target='_blank')
|
||||
.social-icon.svg-icon.instagram(v-html='icons.instagram')
|
||||
a.social-circle(href='https://www.facebook.com/Habitica', target='_blank')
|
||||
.social-icon.facebook.svg-icon(v-html='icons.facebook')
|
||||
.row
|
||||
.col-12.col-md-8 {{ $t('donateText3') }}
|
||||
.col-12.col-md-4
|
||||
button.btn.btn-contribute(@click="donate()", v-if="user")
|
||||
button.btn.btn-contribute.btn-flat(@click="donate()", v-if="user")
|
||||
.svg-icon.heart(v-html="icons.heart")
|
||||
.text {{ $t('companyDonate') }}
|
||||
.btn.btn-contribute(v-else)
|
||||
.btn.btn-contribute.btn-flat(v-else)
|
||||
a(href='http://habitica.fandom.com/wiki/Contributing_to_Habitica', target='_blank')
|
||||
.svg-icon.heart(v-html="icons.heart")
|
||||
.text {{ $t('companyContribute') }}
|
||||
@@ -145,6 +146,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
.icons {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
flex-shrink: 1;
|
||||
}
|
||||
|
||||
// smaller than desktop
|
||||
@media only screen and (max-width: 992px) {
|
||||
.social-circle {
|
||||
height: 32px !important;
|
||||
width: 32px !important;
|
||||
|
||||
margin-left: 0.75em !important;
|
||||
}
|
||||
}
|
||||
|
||||
.social-circle {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
@@ -152,17 +169,20 @@
|
||||
background-color: #c3c0c7;
|
||||
display: flex;
|
||||
margin-left: 1em;
|
||||
float: right;
|
||||
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #a5a1ac;
|
||||
}
|
||||
|
||||
.social-icon {
|
||||
color: #e1e0e3;
|
||||
width: 16px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.instagram {
|
||||
margin-top: .85em;
|
||||
}
|
||||
}
|
||||
|
||||
.logo {
|
||||
@@ -185,6 +205,14 @@
|
||||
box-shadow: none;
|
||||
border-radius: 4px;
|
||||
|
||||
&:hover {
|
||||
background: #a5a1ac;
|
||||
|
||||
.text {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template lang="pug">
|
||||
div
|
||||
.mentioned-icon(v-if='isUserMentioned')
|
||||
.message-hidden(v-if='msg.flagCount === 1 && user.contributor.admin') Message flagged once, not hidden
|
||||
.message-hidden(v-if='msg.flagCount > 1 && user.contributor.admin') Message hidden
|
||||
.message-hidden(v-if='!inbox && msg.flagCount === 1 && user.contributor.admin') Message flagged once, not hidden
|
||||
.message-hidden(v-if='!inbox && msg.flagCount > 1 && user.contributor.admin') Message hidden
|
||||
.card-body
|
||||
user-link(:userId="msg.uuid", :name="msg.user", :backer="msg.backer", :contributor="msg.contributor")
|
||||
p.time
|
||||
@@ -11,25 +11,28 @@ div
|
||||
span(v-b-tooltip="", :title="msg.timestamp | date") {{ msg.timestamp | timeAgo }}
|
||||
span(v-if="msg.client && user.contributor.level >= 4") ({{ msg.client }})
|
||||
.text(v-html='atHighlight(parseMarkdown(msg.text))')
|
||||
.reported(v-if="isMessageReported && (inbox === true)")
|
||||
span(v-once) {{ $t('reportedMessage')}}
|
||||
br
|
||||
span(v-once) {{ $t('canDeleteNow') }}
|
||||
hr
|
||||
.d-flex(v-if='msg.id')
|
||||
.action.d-flex.align-items-center(v-if='!inbox', @click='copyAsTodo(msg)')
|
||||
.svg-icon(v-html="icons.copy")
|
||||
div {{$t('copyAsTodo')}}
|
||||
.action.d-flex.align-items-center(v-if='!inbox && user.flags.communityGuidelinesAccepted && msg.uuid !== "system"', @click='report(msg)')
|
||||
.svg-icon(v-html="icons.report")
|
||||
div {{$t('report')}}
|
||||
// @TODO make flagging/reporting work in the inbox. NOTE: it must work even if the communityGuidelines are not accepted and it MUST work for messages that you have SENT as well as received. -- Alys
|
||||
.action.d-flex.align-items-center(v-if='(inbox || (user.flags.communityGuidelinesAccepted && msg.uuid !== "system")) && (!isMessageReported || user.contributor.admin)', @click='report(msg)')
|
||||
.svg-icon(v-html="icons.report", v-once)
|
||||
div(v-once) {{$t('report')}}
|
||||
.action.d-flex.align-items-center(v-if='msg.uuid === user._id || inbox || user.contributor.admin', @click='remove()')
|
||||
.svg-icon(v-html="icons.delete")
|
||||
| {{$t('delete')}}
|
||||
.svg-icon(v-html="icons.delete", v-once)
|
||||
div(v-once) {{$t('delete')}}
|
||||
.ml-auto.d-flex(v-b-tooltip="{title: likeTooltip(msg.likes[user._id])}", v-if='!inbox')
|
||||
.action.d-flex.align-items-center.mr-0(@click='like()', v-if='likeCount > 0', :class='{active: msg.likes[user._id]}')
|
||||
.svg-icon(v-html="icons.liked", :title='$t("liked")')
|
||||
| +{{ likeCount }}
|
||||
.action.d-flex.align-items-center.mr-0(@click='like()', v-if='likeCount === 0', :class='{active: msg.likes[user._id]}')
|
||||
.svg-icon(v-html="icons.like", :title='$t("like")')
|
||||
span(v-if='!msg.likes[user._id]') {{ $t('like') }}
|
||||
span(v-if='!msg.likes[user._id] && !inbox') {{ $t('like') }}
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@@ -111,6 +114,11 @@ div
|
||||
color: $purple-400;
|
||||
}
|
||||
}
|
||||
|
||||
.reported {
|
||||
margin-top: 18px;
|
||||
color: $red-50;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
@@ -132,8 +140,15 @@ import reportIcon from 'assets/svg/report.svg';
|
||||
import {highlightUsers} from '../../libs/highlightUsers';
|
||||
|
||||
export default {
|
||||
props: ['msg', 'inbox', 'groupId'],
|
||||
components: {userLink},
|
||||
props: {
|
||||
msg: {},
|
||||
inbox: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
groupId: {},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
@@ -143,6 +158,7 @@ export default {
|
||||
delete: deleteIcon,
|
||||
liked: likedIcon,
|
||||
}),
|
||||
reported: false,
|
||||
};
|
||||
},
|
||||
filters: {
|
||||
@@ -191,6 +207,9 @@ export default {
|
||||
}
|
||||
return likeCount;
|
||||
},
|
||||
isMessageReported () {
|
||||
return this.msg.flags && this.msg.flags[this.user.id] || this.reported;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async like () {
|
||||
@@ -216,10 +235,18 @@ export default {
|
||||
copyAsTodo (message) {
|
||||
this.$root.$emit('habitica::copy-as-todo', message);
|
||||
},
|
||||
async report () {
|
||||
report () {
|
||||
this.$root.$on('habitica:report-result', data => {
|
||||
if (data.ok) {
|
||||
this.reported = true;
|
||||
}
|
||||
|
||||
this.$root.$off('habitica:report-result');
|
||||
});
|
||||
|
||||
this.$root.$emit('habitica::report-chat', {
|
||||
message: this.msg,
|
||||
groupId: this.groupId,
|
||||
groupId: this.groupId || 'privateMessage',
|
||||
});
|
||||
},
|
||||
async remove () {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
.row
|
||||
.col-12
|
||||
copy-as-todo-modal(:group-type='groupType', :group-name='groupName', :group-id='groupId')
|
||||
report-flag-modal
|
||||
div(v-for="(msg, index) in messages", v-if='chat && canViewFlag(msg)', :class='{row: inbox}')
|
||||
.d-flex(v-if='user._id !== msg.uuid', :class='{"flex-grow-1": inbox}')
|
||||
avatar.avatar-left(
|
||||
@@ -105,14 +104,21 @@ import findIndex from 'lodash/findIndex';
|
||||
|
||||
import Avatar from '../avatar';
|
||||
import copyAsTodoModal from './copyAsTodoModal';
|
||||
import reportFlagModal from './reportFlagModal';
|
||||
import chatCard from './chatCard';
|
||||
|
||||
export default {
|
||||
props: ['chat', 'groupType', 'groupId', 'groupName', 'inbox'],
|
||||
props: {
|
||||
chat: {},
|
||||
inbox: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
groupType: {},
|
||||
groupId: {},
|
||||
groupName: {},
|
||||
},
|
||||
components: {
|
||||
copyAsTodoModal,
|
||||
reportFlagModal,
|
||||
chatCard,
|
||||
Avatar,
|
||||
},
|
||||
|
||||
@@ -106,14 +106,16 @@ export default {
|
||||
this.$root.$emit('bv::hide::modal', 'report-flag');
|
||||
},
|
||||
async reportAbuse () {
|
||||
this.notify('Thank you for reporting this violation. The moderators have been notified.');
|
||||
this.text(this.$t(this.groupId === 'privateMessage' ? 'pmReported' : 'abuseReported'));
|
||||
|
||||
await this.$store.dispatch('chat:flag', {
|
||||
let result = await this.$store.dispatch('chat:flag', {
|
||||
groupId: this.groupId,
|
||||
chatId: this.abuseObject.id,
|
||||
comment: this.reportComment,
|
||||
});
|
||||
|
||||
this.$root.$emit('habitica:report-result', result);
|
||||
|
||||
this.close();
|
||||
},
|
||||
async clearFlagCount () {
|
||||
|
||||
@@ -139,7 +139,6 @@ b-modal#avatar-modal(title="", :size='editing ? "lg" : "md"', :hide-header='true
|
||||
span 5
|
||||
button.btn.btn-secondary.purchase-all(@click='unlock(`hair.base.${baseHair4Keys.join(",hair.base.")}`)') {{ $t('purchaseAll') }}
|
||||
.col-12.customize-options
|
||||
.head_0.option(@click='set({"preferences.hair.base": 0})', :class="[{ active: user.preferences.hair.base === 0 }, 'hair_base_0_' + user.preferences.hair.color]")
|
||||
.option(v-for='option in baseHair1',
|
||||
:class='{active: user.preferences.hair.base === option}')
|
||||
.base.sprite.customize-option(:class="`hair_base_${option}_${user.preferences.hair.color}`", @click='set({"preferences.hair.base": option})')
|
||||
|
||||
@@ -22,11 +22,11 @@
|
||||
button.btn.btn-primary.btn-lg.btn-block(@click="createGroup()", :disabled="!newGroupIsReady") {{ $t('createGroupPlan') }}
|
||||
.col-12(v-if='activePage === PAGES.PAY')
|
||||
h2 {{ $t('choosePaymentMethod') }}
|
||||
.payment-providers
|
||||
.box.payment-button(@click='pay(PAYMENTS.STRIPE)')
|
||||
.svg-icon.credit-card-icon(v-html="icons.creditCard")
|
||||
.box.payment-button.amazon(@click='pay(PAYMENTS.AMAZON)')
|
||||
.svg-icon.amazon-pay-icon(v-html="icons.amazonpay")
|
||||
.payments-column
|
||||
button.purchase.btn.btn-primary.payment-button.payment-item(@click='pay(PAYMENTS.STRIPE)')
|
||||
.svg-icon.credit-card-icon(v-html="icons.creditCardIcon")
|
||||
| {{ $t('card') }}
|
||||
amazon-button.payment-item(:amazon-data="pay(PAYMENTS.AMAZON)")
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -65,40 +65,29 @@
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.amazon-pay-icon {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.credit-card-icon {
|
||||
width: 150px;
|
||||
color: #4e4a57;
|
||||
}
|
||||
|
||||
.btn-block {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.payment-button.amazon {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import * as Analytics from 'client/libs/analytics';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import paymentsMixin from '../../mixins/payments';
|
||||
import amazonButton from 'client/components/payments/amazonButton';
|
||||
|
||||
import amazonpay from 'assets/svg/amazonpay.svg';
|
||||
import creditCard from 'assets/svg/credit-card.svg';
|
||||
import creditCardIcon from 'assets/svg/credit-card-icon.svg';
|
||||
|
||||
export default {
|
||||
mixins: [paymentsMixin],
|
||||
components: {
|
||||
amazonButton,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
amazonPayments: {},
|
||||
icons: Object.freeze({
|
||||
amazonpay,
|
||||
creditCard,
|
||||
creditCardIcon,
|
||||
}),
|
||||
PAGES: {
|
||||
CREATE_GROUP: 'create-group',
|
||||
@@ -159,7 +148,7 @@ export default {
|
||||
this.showStripe(paymentData);
|
||||
} else if (this.paymentMethod === this.PAYMENTS.AMAZON) {
|
||||
paymentData.type = 'subscription';
|
||||
this.amazonPaymentsInit(paymentData);
|
||||
return paymentData;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<template lang="pug">
|
||||
.row.chat-row
|
||||
.col-12
|
||||
h3(v-once) {{ label }}
|
||||
h3.float-left.label(:class="{accepted: communityGuidelinesAccepted }") {{ label }}
|
||||
div.float-right(v-markdown='$t("markdownFormattingHelp")')
|
||||
|
||||
.row
|
||||
.row(v-if="communityGuidelinesAccepted")
|
||||
textarea(:placeholder='placeholder',
|
||||
v-model='newMessage',
|
||||
ref='user-entry',
|
||||
@@ -22,14 +23,14 @@
|
||||
:caretPosition = 'caretPosition',
|
||||
:chat='group.chat')
|
||||
|
||||
community-guidelines
|
||||
|
||||
.row.chat-actions
|
||||
.col-6.chat-receive-actions
|
||||
button.btn.btn-secondary.float-left.fetch(v-once, @click='fetchRecentMessages()') {{ $t('fetchRecentMessages') }}
|
||||
button.btn.btn-secondary.float-left(v-once, @click='reverseChat()') {{ $t('reverseChat') }}
|
||||
.col-6.chat-send-actions
|
||||
button.btn.btn-secondary.send-chat.float-right(v-once, @click='sendMessage()') {{ $t('send') }}
|
||||
|
||||
community-guidelines
|
||||
button.btn.btn-primary.send-chat.float-right(:disabled="!communityGuidelinesAccepted", @click='sendMessage()') {{ $t('send') }}
|
||||
|
||||
slot(
|
||||
name="additionRow",
|
||||
@@ -46,9 +47,14 @@
|
||||
import autocomplete from '../chat/autoComplete';
|
||||
import communityGuidelines from './communityGuidelines';
|
||||
import chatMessage from '../chat/chatMessages';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import markdownDirective from 'client/directives/markdown';
|
||||
|
||||
export default {
|
||||
props: ['label', 'group', 'placeholder'],
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
},
|
||||
components: {
|
||||
autocomplete,
|
||||
communityGuidelines,
|
||||
@@ -71,9 +77,13 @@
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
currentLength () {
|
||||
return this.newMessage.length;
|
||||
},
|
||||
communityGuidelinesAccepted () {
|
||||
return this.user.flags.communityGuidelinesAccepted;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
// https://medium.com/@_jh3y/how-to-where-s-the-caret-getting-the-xy-position-of-the-caret-a24ba372990a
|
||||
@@ -114,12 +124,22 @@
|
||||
async sendMessage () {
|
||||
if (this.sending) return;
|
||||
this.sending = true;
|
||||
let response = await this.$store.dispatch('chat:postChat', {
|
||||
group: this.group,
|
||||
message: this.newMessage,
|
||||
});
|
||||
this.group.chat.unshift(response.message);
|
||||
this.newMessage = '';
|
||||
let response;
|
||||
|
||||
try {
|
||||
response = await this.$store.dispatch('chat:postChat', {
|
||||
group: this.group,
|
||||
message: this.newMessage,
|
||||
});
|
||||
} catch (e) {
|
||||
// catch exception to allow function to continue
|
||||
}
|
||||
|
||||
if (response) {
|
||||
this.group.chat.unshift(response.message);
|
||||
this.newMessage = '';
|
||||
}
|
||||
|
||||
this.sending = false;
|
||||
|
||||
// @TODO: I would like to not reload everytime we send. Why are we reloading?
|
||||
@@ -196,6 +216,16 @@
|
||||
.chat-row {
|
||||
position: relative;
|
||||
|
||||
.label:not(.accepted) {
|
||||
color: #a5a1ac;
|
||||
}
|
||||
|
||||
.row {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
textarea {
|
||||
min-height: 150px;
|
||||
width: 100%;
|
||||
@@ -204,7 +234,7 @@
|
||||
font-style: italic;
|
||||
line-height: 1.43;
|
||||
color: $gray-300;
|
||||
padding: .5em;
|
||||
padding: 10px 12px;
|
||||
}
|
||||
|
||||
.user-entry {
|
||||
|
||||
@@ -11,17 +11,31 @@
|
||||
|
||||
.community-guidelines {
|
||||
background-color: rgba(135, 129, 144, 0.84);
|
||||
padding: 1em;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
color: $white;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
height: 150px;
|
||||
margin-top: 2.3em;
|
||||
width: 100%;
|
||||
// width: calc(100% - 24px);
|
||||
border-radius: 4px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.col {
|
||||
padding: 20px 24px;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
color: $white;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
button {
|
||||
margin: 20px 12px;
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.btn-follow-guidelines {
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
.svg-icon.shield(v-html="icons.silverGuildBadgeIcon", v-if='group.memberCount > 100 && group.memberCount < 999')
|
||||
.svg-icon.shield(v-html="icons.bronzeGuildBadgeIcon", v-if='group.memberCount < 100')
|
||||
span.number {{ group.memberCount | abbrNum }}
|
||||
div.member-list(v-once) {{ $t('memberList') }}
|
||||
div.member-list.label(v-once) {{ $t('memberList') }}
|
||||
.col-4(v-if='!isParty')
|
||||
.item-with-icon(@click='showGroupGems()')
|
||||
.svg-icon.gem(v-html="icons.gem")
|
||||
span.number {{group.balance * 4}}
|
||||
div(v-once) {{ $t('guildBank') }}
|
||||
div.label(v-once) {{ $t('guildBank') }}
|
||||
chat(
|
||||
:label="$t('chat')",
|
||||
:group="group",
|
||||
@@ -100,6 +100,9 @@
|
||||
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.16), 0 1px 4px 0 rgba(26, 24, 29, 0.12);
|
||||
padding: 1em;
|
||||
text-align: center;
|
||||
min-width: 80px;
|
||||
max-width: 120px;
|
||||
height: 76px;
|
||||
|
||||
.svg-icon.shield, .svg-icon.gem {
|
||||
width: 28px;
|
||||
@@ -115,7 +118,7 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.member-list {
|
||||
.label {
|
||||
margin-top: .5em;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,14 +48,11 @@ div
|
||||
|
||||
.box.payment-providers
|
||||
h3 Choose your payment method
|
||||
.box.payment-button(@click='pay(PAYMENTS.STRIPE)')
|
||||
div
|
||||
.svg-icon.credit-card-icon(v-html="icons.group")
|
||||
p.credit-card Credit Card
|
||||
p Powered by Stripe
|
||||
.box.payment-button(@click='pay(PAYMENTS.AMAZON)')
|
||||
.svg-icon.amazon-pay-icon(v-html="icons.amazonpay")
|
||||
|
||||
.payments-column
|
||||
button.purchase.btn.btn-primary.payment-button.payment-item(@click='pay(PAYMENTS.STRIPE)')
|
||||
.svg-icon.credit-card-icon(v-html="icons.creditCardIcon")
|
||||
| {{ $t('card') }}
|
||||
amazon-button.payment-item(:amazon-data="pay(PAYMENTS.AMAZON)")
|
||||
.container.col-6.offset-3.create-option(v-if='!upgradingGroup._id')
|
||||
.row
|
||||
h1.col-12.text-center.purple-header Create your Group today!
|
||||
@@ -99,13 +96,13 @@ div
|
||||
.form-group
|
||||
button.btn.btn-primary.btn-lg.btn-block(@click="createGroup()", :disabled="!newGroupIsReady") {{ $t('createGroupPlan') }}
|
||||
.col-12(v-if='activePage === PAGES.PAY')
|
||||
.payment-providers
|
||||
.text-center
|
||||
h3 Choose your payment method
|
||||
.box.payment-button(@click='pay(PAYMENTS.STRIPE)')
|
||||
p Credit Card
|
||||
p Powered by Stripe
|
||||
.box.payment-button(@click='pay(PAYMENTS.AMAZON)')
|
||||
| Amazon Pay
|
||||
.payments-column.mx-auto
|
||||
button.purchase.btn.btn-primary.payment-button.payment-item(@click='pay(PAYMENTS.STRIPE)')
|
||||
.svg-icon.credit-card-icon(v-html="icons.creditCardIcon")
|
||||
| {{ $t('card') }}
|
||||
amazon-button.payment-item(:amazon-data="pay(PAYMENTS.AMAZON)")
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -130,12 +127,6 @@ div
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.payment-button {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.plus .svg-icon{
|
||||
width: 24px;
|
||||
}
|
||||
@@ -143,26 +134,6 @@ div
|
||||
.payment-providers {
|
||||
width: 350px;
|
||||
}
|
||||
|
||||
.credit-card {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0;
|
||||
margin-top: .5em;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.credit-card-icon {
|
||||
width: 25px;
|
||||
display: inline-block;
|
||||
margin-right: .5em;
|
||||
}
|
||||
|
||||
.amazon-pay-icon {
|
||||
width: 150px;
|
||||
margin: 0 auto;
|
||||
margin-top: .5em;
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
@@ -316,35 +287,25 @@ div
|
||||
vertical-align: bottom;
|
||||
}
|
||||
}
|
||||
|
||||
.payment-button {
|
||||
width: 200px;
|
||||
height: 80px;
|
||||
margin-bottom: .5em;
|
||||
padding: .5em;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.payment-button:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import paymentsMixin from '../../mixins/payments';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import group from 'assets/svg/group.svg';
|
||||
import amazonpay from 'assets/svg/amazonpay.svg';
|
||||
import positiveIcon from 'assets/svg/positive.svg';
|
||||
import creditCardIcon from 'assets/svg/credit-card-icon.svg';
|
||||
import amazonButton from 'client/components/payments/amazonButton';
|
||||
|
||||
export default {
|
||||
mixins: [paymentsMixin],
|
||||
components: {
|
||||
amazonButton,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
amazonPayments: {},
|
||||
icons: Object.freeze({
|
||||
group,
|
||||
amazonpay,
|
||||
creditCardIcon,
|
||||
positiveIcon,
|
||||
}),
|
||||
PAGES: {
|
||||
@@ -413,7 +374,7 @@ export default {
|
||||
this.showStripe(paymentData);
|
||||
} else if (this.paymentMethod === this.PAYMENTS.AMAZON) {
|
||||
paymentData.type = 'subscription';
|
||||
this.amazonPaymentsInit(paymentData);
|
||||
return paymentData;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
@@ -109,7 +109,7 @@ router-link.card-link(:to="{ name: 'guild', params: { groupId: guild._id } }")
|
||||
|
||||
.member-count {
|
||||
position: relative;
|
||||
top: -3.6em;
|
||||
top: -3.7em;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
line-height: 1.1;
|
||||
|
||||
@@ -3,6 +3,7 @@ div
|
||||
inbox-modal
|
||||
creator-intro
|
||||
profileModal
|
||||
report-flag-modal
|
||||
send-gems-modal
|
||||
b-navbar.topbar.navbar-inverse.static-top(toggleable="lg", type="dark", :class="navbarZIndexClass")
|
||||
b-navbar-brand.brand
|
||||
@@ -351,12 +352,15 @@ import profileModal from '../userMenu/profileModal';
|
||||
import sendGemsModal from 'client/components/payments/sendGemsModal';
|
||||
import userDropdown from './userDropdown';
|
||||
|
||||
import reportFlagModal from '../chat/reportFlagModal';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
creatorIntro,
|
||||
InboxModal,
|
||||
notificationMenu,
|
||||
profileModal,
|
||||
reportFlagModal,
|
||||
sendGemsModal,
|
||||
userDropdown,
|
||||
},
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
v-if="item != null",
|
||||
:hide-header="true",
|
||||
@change="onChange($event)"
|
||||
@hide="fixDocBody()"
|
||||
)
|
||||
div.close
|
||||
span.svg-icon.inline.icon-10(aria-hidden="true", v-html="icons.close", @click="hideDialog()")
|
||||
@@ -187,8 +188,16 @@
|
||||
},
|
||||
hideDialog () {
|
||||
this.$root.$emit('bv::hide::modal', 'equipgear-modal');
|
||||
},
|
||||
fixDocBody () {
|
||||
document.body.classList.remove('modal-open');
|
||||
document.body.setAttribute('data-modal-open-count', document.body.getAttribute('data-modal-open-count') - 1);
|
||||
if (document.body.getAttribute('data-modal-open-count') <= 1) {
|
||||
document.body.removeAttribute('data-modal-open-count');
|
||||
} else {
|
||||
document.body.setAttribute('data-modal-open-count', document.body.getAttribute('data-modal-open-count') - 1);
|
||||
}
|
||||
document.body.removeAttribute('data-padding-right');
|
||||
document.body.style.removeProperty('padding-right');
|
||||
},
|
||||
memberOverrideAvatarGear (gear) {
|
||||
return {
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
)
|
||||
div(
|
||||
v-for="group in itemsGroups",
|
||||
v-if="viewOptions[group.key].selected",
|
||||
v-if="!anyFilterSelected || viewOptions[group.key].selected",
|
||||
:key="group.key",
|
||||
:class='group.key',
|
||||
)
|
||||
@@ -383,10 +383,13 @@ export default {
|
||||
items () {
|
||||
return this.groupBy === 'type' ? this.gearItemsByType : this.gearItemsByClass;
|
||||
},
|
||||
anyFilterSelected () {
|
||||
return Object.values(this.viewOptions).some(g => g.selected);
|
||||
},
|
||||
itemsGroups () {
|
||||
return map(this.groups, (label, group) => {
|
||||
this.$set(this.viewOptions, group, {
|
||||
selected: true,
|
||||
selected: false,
|
||||
open: false,
|
||||
itemsInFirstPosition: [],
|
||||
firstRender: true,
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
b-dropdown-item(@click="sortBy = 'AZ'", :active="sortBy === 'AZ'") {{ $t('AZ') }}
|
||||
div(
|
||||
v-for="group in groups",
|
||||
v-if="group.selected",
|
||||
v-if="!anyFilterSelected || group.selected",
|
||||
:key="group.key",
|
||||
)
|
||||
h2.mb-3
|
||||
@@ -225,7 +225,7 @@ const groups = [
|
||||
return {
|
||||
key: group,
|
||||
quantity: 0,
|
||||
selected: true,
|
||||
selected: false,
|
||||
classPrefix,
|
||||
allowedItems,
|
||||
};
|
||||
@@ -340,6 +340,10 @@ export default {
|
||||
|
||||
return itemsByType;
|
||||
},
|
||||
|
||||
anyFilterSelected () {
|
||||
return this.groups.some(g => g.selected);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
userHasPet (potionKey, eggKey) {
|
||||
@@ -465,8 +469,6 @@ export default {
|
||||
let openedItem = result.data.data;
|
||||
let text = this.content.gear.flat[openedItem.key].text();
|
||||
this.drop(this.$t('messageDropMysteryItem', {dropText: text}), openedItem);
|
||||
item.quantity--;
|
||||
this.$forceUpdate();
|
||||
} else {
|
||||
this.$root.$emit('selectMembersModal::showItem', item);
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
span.badge.badge-pill.badge-default {{countOwnedAnimals(petGroups[0], 'pet')}}
|
||||
|
||||
div(v-for="(petGroup, index) in petGroups",
|
||||
v-if="viewOptions[petGroup.key].selected",
|
||||
v-if="!anyFilterSelected || viewOptions[petGroup.key].selected",
|
||||
:key="petGroup.key")
|
||||
h4(v-if="viewOptions[petGroup.key].animalCount !== 0") {{ petGroup.label }}
|
||||
|
||||
@@ -92,7 +92,11 @@
|
||||
@click="petClicked(item)"
|
||||
)
|
||||
template(slot="itemBadge", slot-scope="context")
|
||||
starBadge(:selected="item.key === currentPet", :show="isOwned('pet', item)", @click="selectPet(item)")
|
||||
starBadge(
|
||||
:selected="context.item.key === currentPet",
|
||||
:show="isOwned('pet', context.item)",
|
||||
@click="selectPet(context.item)"
|
||||
)
|
||||
|
||||
.btn.btn-flat.btn-show-more(@click="setShowMore(petGroup.key)", v-if='petGroup.key !== "specialPets"')
|
||||
| {{ $_openedItemRows_isToggled(petGroup.key) ? $t('showLess') : $t('showMore') }}
|
||||
@@ -103,7 +107,7 @@
|
||||
span.badge.badge-pill.badge-default {{countOwnedAnimals(mountGroups[0], 'mount')}}
|
||||
|
||||
div(v-for="mountGroup in mountGroups",
|
||||
v-if="viewOptions[mountGroup.key].selected",
|
||||
v-if="!anyFilterSelected || viewOptions[mountGroup.key].selected",
|
||||
:key="mountGroup.key")
|
||||
h4(v-if="viewOptions[mountGroup.key].animalCount != 0") {{ mountGroup.label }}
|
||||
|
||||
@@ -469,7 +473,7 @@
|
||||
|
||||
petGroups.map((petGroup) => {
|
||||
this.$set(this.viewOptions, petGroup.key, {
|
||||
selected: true,
|
||||
selected: false,
|
||||
animalCount: 0,
|
||||
});
|
||||
});
|
||||
@@ -514,7 +518,7 @@
|
||||
|
||||
mountGroups.map((mountGroup) => {
|
||||
this.$set(this.viewOptions, mountGroup.key, {
|
||||
selected: true,
|
||||
selected: false,
|
||||
animalCount: 0,
|
||||
});
|
||||
});
|
||||
@@ -538,6 +542,9 @@
|
||||
},
|
||||
];
|
||||
},
|
||||
anyFilterSelected () {
|
||||
return Object.values(this.viewOptions).some(g => g.selected);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
setShowMore (key) {
|
||||
|
||||
@@ -23,21 +23,31 @@
|
||||
span.mr-1(v-if="member.auth && member.auth.local && member.auth.local.username") @{{ member.auth.local.username }}
|
||||
span.mr-1(v-if="member.auth && member.auth.local && member.auth.local.username") •
|
||||
span {{ characterLevel }}
|
||||
.progress-container(v-b-tooltip.hover.bottom="$t('health')")
|
||||
.svg-icon(v-html="icons.health")
|
||||
.progress
|
||||
.progress-bar.bg-health(:style="{width: `${percent(member.stats.hp, MAX_HEALTH)}%`}")
|
||||
span.small-text {{member.stats.hp | statFloor}} / {{MAX_HEALTH}}
|
||||
.progress-container(v-b-tooltip.hover.bottom="$t('experience')")
|
||||
.svg-icon(v-html="icons.experience")
|
||||
.progress
|
||||
.progress-bar.bg-experience(:style="{width: `${percent(member.stats.exp, toNextLevel)}%`}")
|
||||
span.small-text {{member.stats.exp | statFloor}} / {{toNextLevel}}
|
||||
.progress-container(v-if="hasClass", v-b-tooltip.hover.bottom="$t('mana')")
|
||||
.svg-icon(v-html="icons.mana")
|
||||
.progress
|
||||
.progress-bar.bg-mana(:style="{width: `${percent(member.stats.mp, maxMP)}%`}")
|
||||
span.small-text {{member.stats.mp | statFloor}} / {{maxMP}}
|
||||
stats-bar(
|
||||
:icon="icons.health",
|
||||
:value="member.stats.hp",
|
||||
:maxValue="MAX_HEALTH",
|
||||
:tooltip="$t('health')",
|
||||
progressClass="bg-health",
|
||||
:condensed="condensed"
|
||||
)
|
||||
stats-bar(
|
||||
:icon="icons.experience",
|
||||
:value="member.stats.exp",
|
||||
:maxValue="toNextLevel",
|
||||
:tooltip="$t('experience')",
|
||||
progressClass="bg-experience",
|
||||
:condensed="condensed"
|
||||
)
|
||||
stats-bar(
|
||||
v-if="hasClass",
|
||||
:icon="icons.mana",
|
||||
:value="member.stats.mp",
|
||||
:maxValue="maxMP",
|
||||
:tooltip="$t('mana')",
|
||||
progressClass="bg-mana",
|
||||
:condensed="condensed"
|
||||
)
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -99,44 +109,6 @@
|
||||
margin-bottom: .5em
|
||||
}
|
||||
|
||||
.progress-container {
|
||||
margin-left: 4px;
|
||||
margin-bottom: .5em;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.progress-container > span {
|
||||
color: $header-color;
|
||||
margin-left: 8px;
|
||||
font-style: normal;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.progress-container > .svg-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.progress-container > .progress {
|
||||
min-width: 200px;
|
||||
margin: 0px;
|
||||
border-radius: 2px;
|
||||
height: 12px;
|
||||
background-color: $header-dark-background;
|
||||
}
|
||||
|
||||
.progress-container > .progress > .progress-bar {
|
||||
border-radius: 2px;
|
||||
height: 12px;
|
||||
min-width: 0px;
|
||||
}
|
||||
|
||||
.progress-container .svg-icon, .progress-container .progress, .progress-container .small-text {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
// Condensed version
|
||||
.member-details.condensed.expanded {
|
||||
background: $header-dark-background;
|
||||
@@ -163,25 +135,6 @@
|
||||
border-bottom-left-radius: 4px;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
.progress-container > .svg-icon {
|
||||
width: 19px;
|
||||
height: 19px;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
.progress-container > .progress {
|
||||
width: 152px;
|
||||
border-radius: 0px;
|
||||
height: 10px;
|
||||
margin-top: 2px;
|
||||
background: $purple-100;
|
||||
}
|
||||
|
||||
.progress-container > .progress > .progress-bar {
|
||||
border-radius: 0px;
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -190,6 +143,7 @@ import Avatar from './avatar';
|
||||
import ClassBadge from './members/classBadge';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import Profile from './userMenu/profile';
|
||||
import StatsBar from './ui/statsbar';
|
||||
|
||||
import { toNextLevel } from '../../common/script/statHelpers';
|
||||
import statsComputed from '../../common/script/libs/statsComputed';
|
||||
@@ -205,9 +159,7 @@ export default {
|
||||
Avatar,
|
||||
Profile,
|
||||
ClassBadge,
|
||||
},
|
||||
directives: {
|
||||
// bTooltip,
|
||||
StatsBar,
|
||||
},
|
||||
props: {
|
||||
member: {
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
<template lang="pug">
|
||||
.amazon-pay-button(:id="buttonId")
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import { mapState } from 'client/libs/store';
|
||||
import uuid from 'uuid';
|
||||
import paymentsMixin from 'client/mixins/payments';
|
||||
|
||||
const AMAZON_PAYMENTS = process.env.AMAZON_PAYMENTS; // eslint-disable-line
|
||||
|
||||
export default {
|
||||
mixins: [paymentsMixin],
|
||||
data () {
|
||||
return { // @TODO what needed here? can be moved to mixin?
|
||||
amazonPayments: {
|
||||
modal: null,
|
||||
type: null,
|
||||
gift: null,
|
||||
loggedIn: false,
|
||||
paymentSelected: false,
|
||||
billingAgreementId: '',
|
||||
recurringConsent: false,
|
||||
orderReferenceId: null,
|
||||
subscription: null,
|
||||
coupon: null,
|
||||
},
|
||||
isAmazonSetup: false,
|
||||
amazonButtonEnabled: false,
|
||||
groupToCreate: null, // creating new group
|
||||
group: null, // upgrading existing group
|
||||
buttonId: null,
|
||||
};
|
||||
},
|
||||
props: {
|
||||
amazonData: Object,
|
||||
amazonDisabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
...mapState(['isAmazonReady']),
|
||||
amazonPaymentsCanCheckout () {
|
||||
if (this.amazonPayments.type === 'single') {
|
||||
return this.amazonPayments.paymentSelected === true;
|
||||
} else if (this.amazonPayments.type === 'subscription') {
|
||||
return this.amazonPayments.paymentSelected && this.amazonPayments.recurringConsent;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
amazonData () {
|
||||
this.amazonPaymentsInit(this.amazonData);
|
||||
},
|
||||
},
|
||||
beforeMount () {
|
||||
this.buttonId = `AmazonPayButton-${uuid.v4()}`;
|
||||
},
|
||||
mounted () {
|
||||
this.amazonPaymentsInit(this.amazonData);
|
||||
if (this.isAmazonReady) return this.setupAmazon();
|
||||
|
||||
this.$store.watch(state => state.isAmazonReady, (isAmazonReady) => {
|
||||
if (isAmazonReady) return this.setupAmazon();
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
setupAmazon () {
|
||||
if (this.isAmazonSetup) return false;
|
||||
this.isAmazonSetup = true;
|
||||
this.showButton();
|
||||
},
|
||||
showButton () {
|
||||
window.OffAmazonPayments.Button( // eslint-disable-line new-cap
|
||||
this.buttonId, // ID of the button
|
||||
AMAZON_PAYMENTS.SELLER_ID,
|
||||
{
|
||||
type: 'PwA',
|
||||
color: 'Gold',
|
||||
size: 'large',
|
||||
agreementType: 'BillingAgreement',
|
||||
onSignIn: async (contract) => { // @TODO send to modal
|
||||
if (this.amazonDisabled === true) return null;
|
||||
// if (!this.checkGemAmount(this.amazonData)) return;
|
||||
this.amazonPayments.billingAgreementId = contract.getAmazonBillingAgreementId();
|
||||
|
||||
this.$set(this.amazonPayments, 'loggedIn', true);
|
||||
|
||||
this.$root.$emit('habitica::pay-with-amazon', this.amazonPayments);
|
||||
},
|
||||
authorization: () => {
|
||||
if (this.amazonDisabled === true) return null;
|
||||
window.amazon.Login.authorize({
|
||||
scope: 'payments:widget',
|
||||
popup: true,
|
||||
}, function amazonSuccess (response) {
|
||||
if (response.error) return alert(response.error);
|
||||
|
||||
const url = '/amazon/verifyAccessToken';
|
||||
axios.post(url, response).catch((e) => {
|
||||
alert(e.message);
|
||||
});
|
||||
});
|
||||
},
|
||||
onError: this.amazonOnError, // @TODO port here
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,7 +1,6 @@
|
||||
<template lang="pug">
|
||||
b-modal#amazon-payment(title="Amazon", :hide-footer="true", size='md')
|
||||
h2.text-center Continue with Amazon
|
||||
#AmazonPayButton
|
||||
#AmazonPayWallet(v-if="amazonPayments.loggedIn", style="width: 400px; height: 228px;")
|
||||
template(v-if="amazonPayments.loggedIn && amazonPayments.type === 'subscription'")
|
||||
br
|
||||
@@ -19,7 +18,7 @@
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
#AmazonPayButton, #AmazonPayWallet, #AmazonPayRecurring {
|
||||
#AmazonPayWallet, #AmazonPayRecurring {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@@ -54,7 +53,6 @@ export default {
|
||||
subscription: null,
|
||||
coupon: null,
|
||||
},
|
||||
OffAmazonPayments: {},
|
||||
isAmazonSetup: false,
|
||||
amazonButtonEnabled: false,
|
||||
groupToCreate: null, // creating new group
|
||||
@@ -74,12 +72,6 @@ export default {
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
if (this.isAmazonReady) return this.setupAmazon();
|
||||
|
||||
this.$store.watch(state => state.isAmazonReady, (isAmazonReady) => {
|
||||
if (isAmazonReady) return this.setupAmazon();
|
||||
});
|
||||
|
||||
this.$root.$on('habitica::pay-with-amazon', (amazonPaymentsData) => {
|
||||
if (!amazonPaymentsData) return;
|
||||
|
||||
@@ -90,67 +82,30 @@ export default {
|
||||
this.amazonPayments = Object.assign({}, amazonPayments, amazonPaymentsData);
|
||||
|
||||
this.$root.$emit('bv::show::modal', 'amazon-payment');
|
||||
|
||||
this.$nextTick(async () => {
|
||||
if (this.amazonPayments.type === 'subscription') {
|
||||
this.amazonInitWidgets();
|
||||
} else {
|
||||
let url = '/amazon/createOrderReferenceId';
|
||||
let response = await axios.post(url, {
|
||||
billingAgreementId: this.amazonPayments.billingAgreementId,
|
||||
});
|
||||
|
||||
if (response.status <= 400) {
|
||||
this.amazonPayments.orderReferenceId = response.data.data.orderReferenceId;
|
||||
this.amazonInitWidgets();
|
||||
} else {
|
||||
alert(response.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
destroyed () {
|
||||
this.$root.$off('habitica::pay-with-amazon');
|
||||
},
|
||||
methods: {
|
||||
setupAmazon () {
|
||||
if (this.isAmazonSetup) return false;
|
||||
this.isAmazonSetup = true;
|
||||
this.OffAmazonPayments = window.OffAmazonPayments;
|
||||
this.showButton();
|
||||
},
|
||||
showButton () {
|
||||
// @TODO: prevent modal close form clicking outside
|
||||
let amazonButton = this.OffAmazonPayments.Button( // eslint-disable-line
|
||||
'AmazonPayButton',
|
||||
AMAZON_PAYMENTS.SELLER_ID,
|
||||
{
|
||||
type: 'PwA',
|
||||
color: 'Gold',
|
||||
size: 'small',
|
||||
agreementType: 'BillingAgreement',
|
||||
onSignIn: async (contract) => {
|
||||
this.amazonPayments.billingAgreementId = contract.getAmazonBillingAgreementId();
|
||||
|
||||
this.$set(this.amazonPayments, 'loggedIn', true);
|
||||
|
||||
if (this.amazonPayments.type === 'subscription') {
|
||||
this.amazonInitWidgets();
|
||||
} else {
|
||||
let url = '/amazon/createOrderReferenceId';
|
||||
let response = await axios.post(url, {
|
||||
billingAgreementId: this.amazonPayments.billingAgreementId,
|
||||
});
|
||||
|
||||
if (response.status <= 400) {
|
||||
this.amazonPayments.orderReferenceId = response.data.data.orderReferenceId;
|
||||
this.amazonInitWidgets();
|
||||
return;
|
||||
}
|
||||
|
||||
alert(response.message);
|
||||
}
|
||||
},
|
||||
authorization: () => {
|
||||
window.amazon.Login.authorize({
|
||||
scope: 'payments:widget',
|
||||
popup: true,
|
||||
}, function amazonSuccess (response) {
|
||||
if (response.error) return alert(response.error);
|
||||
|
||||
let url = '/amazon/verifyAccessToken';
|
||||
axios.post(url, response)
|
||||
.catch((e) => {
|
||||
alert(e.message);
|
||||
});
|
||||
});
|
||||
},
|
||||
onError: this.amazonOnError,
|
||||
});
|
||||
},
|
||||
amazonInitWidgets () {
|
||||
let walletParams = {
|
||||
sellerId: AMAZON_PAYMENTS.SELLER_ID, // @TODO: Import
|
||||
@@ -167,15 +122,14 @@ export default {
|
||||
walletParams.onReady = (billingAgreement) => {
|
||||
this.amazonPayments.billingAgreementId = billingAgreement.getAmazonBillingAgreementId();
|
||||
|
||||
new this.OffAmazonPayments.Widgets.Consent({
|
||||
new window.OffAmazonPayments.Widgets.Consent({
|
||||
sellerId: AMAZON_PAYMENTS.SELLER_ID,
|
||||
amazonBillingAgreementId: this.amazonPayments.billingAgreementId,
|
||||
design: {
|
||||
designMode: 'responsive',
|
||||
},
|
||||
onReady: (consent) => {
|
||||
let getConsent = consent.getConsentStatus;
|
||||
this.$set(this.amazonPayments, 'recurringConsent', getConsent ? Boolean(getConsent()) : false);
|
||||
this.$set(this.amazonPayments, 'recurringConsent', consent.getConsentStatus ? Boolean(consent.getConsentStatus()) : false);
|
||||
this.$set(this, 'amazonButtonEnabled', true);
|
||||
},
|
||||
onConsent: (consent) => {
|
||||
@@ -189,7 +143,7 @@ export default {
|
||||
walletParams.amazonOrderReferenceId = this.amazonPayments.orderReferenceId;
|
||||
}
|
||||
|
||||
new this.OffAmazonPayments.Widgets.Wallet(walletParams).bind('AmazonPayWallet');
|
||||
new window.OffAmazonPayments.Widgets.Wallet(walletParams).bind('AmazonPayWallet');
|
||||
},
|
||||
storePaymentStatusAndReload (url) {
|
||||
let paymentType;
|
||||
@@ -305,30 +259,6 @@ export default {
|
||||
amazonOnPaymentSelect () {
|
||||
this.$set(this.amazonPayments, 'paymentSelected', true);
|
||||
},
|
||||
amazonOnError (error) {
|
||||
alert(error.getErrorMessage());
|
||||
this.reset();
|
||||
},
|
||||
reset () {
|
||||
// @TODO: Ensure we are using all of these
|
||||
// some vars are set in the payments mixin. We should try to edit in one place
|
||||
this.amazonPayments.modal = null;
|
||||
this.amazonPayments.type = null;
|
||||
this.amazonPayments.loggedIn = false;
|
||||
|
||||
// Gift
|
||||
this.amazonPayments.gift = null;
|
||||
this.amazonPayments.giftReceiver = null;
|
||||
|
||||
this.amazonPayments.billingAgreementId = null;
|
||||
this.amazonPayments.orderReferenceId = null;
|
||||
this.amazonPayments.paymentSelected = false;
|
||||
this.amazonPayments.recurringConsent = false;
|
||||
this.amazonPayments.subscription = null;
|
||||
this.amazonPayments.coupon = null;
|
||||
this.amazonPayments.groupToCreate = null;
|
||||
this.amazonPayments.group = null;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -44,16 +44,15 @@
|
||||
button.btn.btn-primary(@click='gemAmount === 20 ? gemAmount = 0 : gemAmount = 20') {{gemAmount === 20 ? $t('selected') : '$5.00'}}
|
||||
.row.text-center
|
||||
h2.mx-auto.text-payment {{ $t('choosePaymentMethod') }}
|
||||
.card-deck
|
||||
.card.text-center.payment-method(@click='showStripe({})')
|
||||
.card-body
|
||||
.mx-auto(v-html='icons.creditCard', style='"height: 56px; width: 159px; margin-top: 1em;"')
|
||||
.card.text-center.payment-method
|
||||
a.card-body.paypal(@click="openPaypal(paypalCheckoutLink, 'gems')")
|
||||
img(src='~assets/images/paypal.png')
|
||||
.card.text-center.payment-method(@click="amazonPaymentsInit({type: 'single'})")
|
||||
.card-body.amazon
|
||||
img(src='~assets/images/amazon-payments.png')
|
||||
.payments-column
|
||||
button.purchase.btn.btn-primary.payment-button.payment-item(@click='showStripe({})')
|
||||
.svg-icon.credit-card-icon(v-html="icons.creditCardIcon")
|
||||
| {{ $t('card') }}
|
||||
button.btn.payment-item.paypal-checkout.payment-button(@click="openPaypal(paypalCheckoutLink, 'gems')")
|
||||
|
|
||||
img(src='~assets/images/paypal-checkout.png', :alt="$t('paypal')")
|
||||
|
|
||||
amazon-button.payment-item(:amazon-data="{type: 'single'}")
|
||||
.row.text-center
|
||||
.svg-icon.mx-auto(v-html='icons.heart', style='"height: 24px; width: 24px;"')
|
||||
.row.text-center.text-outtro
|
||||
@@ -127,16 +126,16 @@
|
||||
h2.mx-auto.text-payment(v-once) {{ $t('choosePaymentMethod') }}
|
||||
.row.text-center
|
||||
a.mx-auto(v-once) {{ $t('haveCouponCode') }}
|
||||
.card-deck(v-if='subscriptionPlan')
|
||||
.card.text-center.payment-method
|
||||
.card-body(@click='showStripe({subscription: subscriptionPlan})')
|
||||
.mx-auto(v-html='icons.creditCard', style='"height: 56px; width: 159px; margin-top: 1em;"')
|
||||
.card.text-center.payment-method
|
||||
a.card-body.paypal(@click="openPaypal(paypalSubscriptionLink, 'subscription')")
|
||||
img(src='~assets/images/paypal.png')
|
||||
.card.text-center.payment-method
|
||||
.card-body.amazon(@click="amazonPaymentsInit({type: 'subscription', subscription: subscriptionPlan})")
|
||||
img(src='~assets/images/amazon-payments.png')
|
||||
.payments-column(v-if='subscriptionPlan')
|
||||
button.purchase.btn.btn-primary.payment-button.payment-item(@click='showStripe({subscription: subscriptionPlan})')
|
||||
.svg-icon.credit-card-icon(v-html="icons.creditCardIcon")
|
||||
| {{ $t('card') }}
|
||||
button.btn.payment-item.paypal-checkout.payment-button(@click="openPaypal(paypalSubscriptionLink, 'subscription')")
|
||||
|
|
||||
img(src='~assets/images/paypal-checkout.png', :alt="$t('paypal')")
|
||||
|
|
||||
amazon-button.payment-item(:amazon-data="{type: 'subscription', subscription: subscriptionPlan}")
|
||||
|
||||
.row.text-center
|
||||
.svg-icon.mx-auto(v-html='icons.heart', style='"height: 24px; width: 24px;"')
|
||||
.row.text-center.text-outtro
|
||||
@@ -162,6 +161,11 @@
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
|
||||
.payments-column {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
a.mx-auto {
|
||||
color: #2995cd;
|
||||
}
|
||||
@@ -174,10 +178,6 @@
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.amazon {
|
||||
padding-top: 1.8em;
|
||||
}
|
||||
|
||||
.benefits {
|
||||
font-size: 14px;
|
||||
}
|
||||
@@ -194,19 +194,6 @@
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: 1em;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 2px 2px 0 rgba(26, 24, 29, 0.16), 0 1px 4px 0 rgba(26, 24, 29, 0.12);
|
||||
}
|
||||
|
||||
.card.active {
|
||||
border-color: #24cc8f;
|
||||
button {
|
||||
background-color: #24cc8f;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
width: 80%;
|
||||
height: 1px;
|
||||
@@ -272,18 +259,6 @@
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.payment-method {
|
||||
background-color: #e1e0e3;
|
||||
}
|
||||
|
||||
.payment-method:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.paypal {
|
||||
padding-top: 1.3em;
|
||||
}
|
||||
|
||||
.spacer {
|
||||
height: 4em;
|
||||
}
|
||||
@@ -328,7 +303,6 @@
|
||||
color: #4e4a57;
|
||||
font-size: 24px;
|
||||
margin: 1em;
|
||||
opacity: 0.64;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -339,7 +313,7 @@
|
||||
import paymentsMixin from 'client/mixins/payments';
|
||||
|
||||
import checkIcon from 'assets/svg/check.svg';
|
||||
import creditCard from 'assets/svg/credit-card.svg';
|
||||
import creditCardIcon from 'assets/svg/credit-card-icon.svg';
|
||||
import heart from 'assets/svg/health.svg';
|
||||
import logo from 'assets/svg/habitica-logo.svg';
|
||||
|
||||
@@ -348,10 +322,13 @@
|
||||
import fortyTwoGems from 'assets/svg/42-gems.svg';
|
||||
import eightyFourGems from 'assets/svg/84-gems.svg';
|
||||
|
||||
import amazonButton from 'client/components/payments/amazonButton';
|
||||
|
||||
export default {
|
||||
mixins: [paymentsMixin],
|
||||
components: {
|
||||
planGemLimits,
|
||||
amazonButton,
|
||||
},
|
||||
computed: {
|
||||
...mapState({user: 'user.data'}),
|
||||
@@ -373,7 +350,7 @@
|
||||
icons: Object.freeze({
|
||||
logo,
|
||||
check: checkIcon,
|
||||
creditCard,
|
||||
creditCardIcon,
|
||||
fourGems,
|
||||
heart,
|
||||
twentyOneGems,
|
||||
@@ -383,7 +360,6 @@
|
||||
gemAmount: 0,
|
||||
subscriptionPlan: '',
|
||||
selectedPage: 'subscribe',
|
||||
amazonPayments: {},
|
||||
planGemLimits,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template lang="pug">
|
||||
b-modal#send-gems(:title="title", :hide-footer="true", size='lg', @hide='onHide()')
|
||||
.modal-body(v-if='userReceivingGems')
|
||||
b-modal#send-gems(:title="title", :hide-footer="true", size='md', @hide='onHide()')
|
||||
div(v-if='userReceivingGems')
|
||||
.panel.panel-default(
|
||||
:class="gift.type === 'gems' ? 'panel-primary' : 'transparent'",
|
||||
@click='gift.type = "gems"'
|
||||
@@ -32,7 +32,7 @@ b-modal#send-gems(:title="title", :hide-footer="true", size='lg', @hide='onHide(
|
||||
h3.panel-heading {{ $t('subscription') }}
|
||||
.panel-body
|
||||
.row
|
||||
.col-md-4
|
||||
.col-md-12
|
||||
.form-group
|
||||
.radio(v-for='block in subscriptionBlocks', v-if="block.target !== 'group' && block.canSubscribe === true")
|
||||
label
|
||||
@@ -48,11 +48,18 @@ b-modal#send-gems(:title="title", :hide-footer="true", size='lg', @hide='onHide(
|
||||
@click="sendGift()",
|
||||
:disabled="sendingInProgress"
|
||||
) {{ $t("send") }}
|
||||
template(v-else)
|
||||
button.btn.btn-primary(@click='showStripe({gift, uuid: userReceivingGems._id, receiverName})') {{ $t('card') }}
|
||||
button.btn.btn-warning(@click='openPaypalGift({gift: gift, giftedTo: userReceivingGems._id, receiverName})') PayPal
|
||||
button.btn.btn-success(@click="amazonPaymentsInit({type: 'single', gift, giftedTo: userReceivingGems._id, receiverName})") Amazon Payments
|
||||
button.btn.btn-secondary(@click='close()') {{$t('cancel')}}
|
||||
.payments-column.mx-auto(v-else, :class="{'payments-disabled': !gift.subscription.key && gift.gems.amount < 1}")
|
||||
button.purchase.btn.btn-primary.payment-button.payment-item(@click='showStripe({gift, uuid: userReceivingGems._id, receiverName})', :disabled="!gift.subscription.key && gift.gems.amount < 1")
|
||||
.svg-icon.credit-card-icon(v-html="icons.creditCardIcon")
|
||||
| {{ $t('card') }}
|
||||
button.btn.payment-item.paypal-checkout.payment-button(@click="openPaypalGift({gift: gift, giftedTo: userReceivingGems._id, receiverName})", :disabled="!gift.subscription.key && gift.gems.amount < 1")
|
||||
|
|
||||
img(src='~assets/images/paypal-checkout.png', :alt="$t('paypal')")
|
||||
|
|
||||
amazon-button.payment-item.mb-0(
|
||||
:amazon-data="{type: 'single', gift, giftedTo: userReceivingGems._id, receiverName}",
|
||||
:amazon-disabled="!gift.subscription.key && gift.gems.amount < 1",
|
||||
)
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
@@ -78,6 +85,12 @@ b-modal#send-gems(:title="title", :hide-footer="true", size='lg', @hide='onHide(
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
input[type="radio"] {
|
||||
margin-right: 4px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import toArray from 'lodash/toArray';
|
||||
import omitBy from 'lodash/omitBy';
|
||||
@@ -86,12 +99,17 @@ import { mapState } from 'client/libs/store';
|
||||
import planGemLimits from '../../../common/script/libs/planGemLimits';
|
||||
import paymentsMixin from 'client/mixins/payments';
|
||||
import notificationsMixin from 'client/mixins/notifications';
|
||||
import amazonButton from 'client/components/payments/amazonButton';
|
||||
import creditCardIcon from 'assets/svg/credit-card-icon.svg';
|
||||
|
||||
// @TODO: EMAILS.TECH_ASSISTANCE_EMAIL, load from config
|
||||
const TECH_ASSISTANCE_EMAIL = 'admin@habitica.com';
|
||||
|
||||
export default {
|
||||
mixins: [paymentsMixin, notificationsMixin],
|
||||
components: {
|
||||
amazonButton,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
planGemLimits,
|
||||
@@ -110,6 +128,9 @@ export default {
|
||||
},
|
||||
sendingInProgress: false,
|
||||
userReceivingGems: null,
|
||||
icons: Object.freeze({
|
||||
creditCardIcon,
|
||||
}),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
span(v-html="$t(paymentData.newGroup ? 'groupPlanCreated' : 'groupPlanUpgraded', {groupName: paymentData.group.name})")
|
||||
.details-block
|
||||
span(v-html="$t('paymentSubBilling', {amount: groupPlanCost, months: paymentData.subscription.months})")
|
||||
template(v-if="paymentData.paymentType === 'groupPlan' || paymentData.paymentType === 'subscription'")
|
||||
span.small-text.auto-renew(v-once) {{ $t('paymentAutoRenew') }}
|
||||
button.btn.btn-primary(@click='close()', v-once) {{$t('onwards')}}
|
||||
</template>
|
||||
|
||||
@@ -116,6 +118,12 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.auto-renew {
|
||||
margin-top: 16px;
|
||||
color: $orange-10;
|
||||
font-style: normal;
|
||||
}
|
||||
}
|
||||
|
||||
#payments-success-modal .modal-footer {
|
||||
|
||||
@@ -73,15 +73,15 @@
|
||||
|
||||
.subscribe-pay(v-if='!hasSubscription || hasCanceledSubscription')
|
||||
h3 {{ $t('subscribeUsing') }}
|
||||
.row.text-center
|
||||
.col-md-4
|
||||
button.purchase.btn.btn-primary(@click='showStripe({subscription:subscription.key, coupon:subscription.coupon})', :disabled='!subscription.key') {{ $t('card') }}
|
||||
.col-md-4
|
||||
a.purchase(@click="openPaypal(paypalPurchaseLink, 'subscription')", :disabled='!subscription.key')
|
||||
img(src='https://www.paypalobjects.com/webstatic/en_US/i/buttons/pp-acceptance-small.png', :alt="$t('paypal')")
|
||||
.col-md-4
|
||||
a.btn.btn-secondary.purchase(@click="payWithAmazon()")
|
||||
img(src='https://payments.amazon.com/gp/cba/button', :alt="$t('amazonPayments')")
|
||||
.payments-column
|
||||
button.purchase.btn.btn-primary.payment-button.payment-item(@click='showStripe({subscription:subscription.key, coupon:subscription.coupon})', :disabled='!subscription.key')
|
||||
.svg-icon.credit-card-icon(v-html="icons.creditCardIcon")
|
||||
| {{ $t('card') }}
|
||||
button.btn.payment-item.paypal-checkout.payment-button(@click="openPaypal(paypalPurchaseLink, 'subscription')", :disabled='!subscription.key')
|
||||
|
|
||||
img(src='~assets/images/paypal-checkout.png', :alt="$t('paypal')")
|
||||
|
|
||||
amazon-button.payment-item(:amazon-data="{type: 'subscription', subscription: this.subscription.key, coupon: this.subscription.coupon}")
|
||||
.row
|
||||
.col-6
|
||||
h2(v-once) {{ $t('giftSubscription') }}
|
||||
@@ -92,7 +92,7 @@
|
||||
h4(v-once) {{ $t('giftSubscriptionText4') }}
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
<style scoped lang="scss">
|
||||
.badge.badge-success {
|
||||
color: #fff;
|
||||
}
|
||||
@@ -115,8 +115,14 @@ import planGemLimits from '../../../common/script/libs/planGemLimits';
|
||||
import paymentsMixin from '../../mixins/payments';
|
||||
import notificationsMixin from '../../mixins/notifications';
|
||||
|
||||
import amazonButton from 'client/components/payments/amazonButton';
|
||||
import creditCardIcon from 'assets/svg/credit-card-icon.svg';
|
||||
|
||||
export default {
|
||||
mixins: [paymentsMixin, notificationsMixin],
|
||||
components: {
|
||||
amazonButton,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
@@ -137,6 +143,9 @@ export default {
|
||||
PAYPAL: 'Paypal',
|
||||
GIFT: 'Gift',
|
||||
},
|
||||
icons: Object.freeze({
|
||||
creditCardIcon,
|
||||
}),
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -240,13 +249,6 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
payWithAmazon () {
|
||||
this.amazonPaymentsInit({
|
||||
type: 'subscription',
|
||||
subscription: this.subscription.key,
|
||||
coupon: this.subscription.coupon,
|
||||
});
|
||||
},
|
||||
async applyCoupon (coupon) {
|
||||
const response = await axios.post(`/api/v4/coupons/validate/${coupon}`);
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ layout-section(:title="$t('equipment')")
|
||||
span(slot="item", slot-scope="ctx")
|
||||
span.text {{ $t(ctx.item.id) }}
|
||||
|
||||
itemRows(
|
||||
itemRows.equipment-rows(
|
||||
:items="sortedGearItems",
|
||||
:itemWidth=94,
|
||||
:itemMargin=24,
|
||||
@@ -169,6 +169,10 @@ layout-section(:title="$t('equipment')")
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.equipment-rows {
|
||||
/deep/ .item.item-empty {
|
||||
background: white;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
h1.mb-4.page-header(v-once) {{ $t('market') }}
|
||||
|
||||
equipment-section(
|
||||
v-if="viewOptions['equipment'].selected",
|
||||
v-if="!anyFilterSelected || viewOptions['equipment'].selected",
|
||||
:hidePinned="hidePinned",
|
||||
:hideLocked="hideLocked",
|
||||
:searchBy="searchTextThrottled"
|
||||
@@ -39,17 +39,17 @@
|
||||
span.text {{ $t(ctx.item.id) }}
|
||||
div(
|
||||
v-for="category in categories",
|
||||
v-if="viewOptions[category.identifier].selected && category.identifier !== 'equipment'"
|
||||
v-if="!anyFilterSelected || viewOptions[category.identifier].selected && category.identifier !== 'equipment'"
|
||||
)
|
||||
h4 {{ category.text }}
|
||||
category-row(
|
||||
:hidePinned="hidePinned",
|
||||
:hideLocked="hideLocked",
|
||||
:searchBy="searchTextThrottled",
|
||||
:sortBy="selectedSortItemsBy.id",
|
||||
:category="category"
|
||||
)
|
||||
keys-to-kennel(v-if='category.identifier === "special"')
|
||||
category-row(
|
||||
:hidePinned="hidePinned",
|
||||
:hideLocked="hideLocked",
|
||||
:searchBy="searchTextThrottled",
|
||||
:sortBy="selectedSortItemsBy.id",
|
||||
:category="category"
|
||||
)
|
||||
keys-to-kennel(v-if='category.identifier === "special"')
|
||||
div.fill-height
|
||||
|
||||
inventoryDrawer(:showEggs="true", :showPotions="true")
|
||||
@@ -290,13 +290,16 @@ export default {
|
||||
categories.map((category) => {
|
||||
if (!this.viewOptions[category.identifier]) {
|
||||
this.$set(this.viewOptions, category.identifier, {
|
||||
selected: true,
|
||||
selected: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return categories;
|
||||
},
|
||||
anyFilterSelected () {
|
||||
return Object.values(this.viewOptions).some(g => g.selected);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
sellItem (itemScope) {
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
br
|
||||
|
||||
div(v-else)
|
||||
div(v-once)
|
||||
div
|
||||
div.text {{ item.notes() }}
|
||||
|
||||
div
|
||||
|
||||
@@ -52,11 +52,6 @@
|
||||
:popoverPosition="'top'",
|
||||
@click="selectItem(item)"
|
||||
)
|
||||
template(slot="popoverContent", slot-scope="ctx")
|
||||
div.questPopover
|
||||
h4.popover-content-title {{ item.text }}
|
||||
questInfo(:quest="item")
|
||||
|
||||
template(slot="itemBadge", slot-scope="ctx")
|
||||
span.badge.badge-pill.badge-item.badge-svg(
|
||||
:class="{'item-selected-badge': ctx.item.pinned, 'hide': !ctx.item.pinned}",
|
||||
@@ -81,7 +76,7 @@
|
||||
|
||||
div(
|
||||
v-for="category in categories",
|
||||
v-if="viewOptions[category.identifier].selected"
|
||||
v-if="!anyFilterSelected || viewOptions[category.identifier].selected"
|
||||
)
|
||||
h2.mb-3 {{ category.text }}
|
||||
|
||||
@@ -244,20 +239,22 @@
|
||||
display: inline-block;
|
||||
width: 33%;
|
||||
margin-bottom: 24px;
|
||||
vertical-align: top;
|
||||
|
||||
.items {
|
||||
border-radius: 2px;
|
||||
background-color: #edecee;
|
||||
display: inline-block;
|
||||
padding: 8px;
|
||||
padding: 0;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.item-wrapper {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.items > div:not(:last-of-type) {
|
||||
margin-right: 16px;
|
||||
.items > div {
|
||||
margin: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -415,7 +412,7 @@ export default {
|
||||
if (this.shop.categories) {
|
||||
this.shop.categories.map((category) => {
|
||||
this.$set(this.viewOptions, category.identifier, {
|
||||
selected: true,
|
||||
selected: false,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -424,6 +421,10 @@ export default {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
|
||||
anyFilterSelected () {
|
||||
return Object.values(this.viewOptions).some(g => g.selected);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
questItems (category, sortBy, searchBy, hideLocked, hidePinned) {
|
||||
|
||||
@@ -1,41 +1,60 @@
|
||||
<template lang="pug">
|
||||
.row(:class="{'small-version': smallVersion}")
|
||||
dl
|
||||
template(v-if="quest.collect")
|
||||
dt(:class="smallVersion ? 'col-3' : 'col-4'") {{ $t('collect') + ':' }}
|
||||
dd.col-8
|
||||
.table-row(v-if="quest.collect")
|
||||
dt {{ $t('collect') + ':' }}
|
||||
dd
|
||||
div(v-for="(collect, key) of quest.collect")
|
||||
span {{ collect.count }} {{ getCollectText(collect) }}
|
||||
|
||||
template(v-if="quest.boss")
|
||||
dt(:class="smallVersion ? 'col-3' : 'col-4'") {{ $t('bossHP') + ':' }}
|
||||
dd.col-8 {{ quest.boss.hp }}
|
||||
.table-row(v-if="quest.boss")
|
||||
dt {{ $t('bossHP') + ':' }}
|
||||
dd {{ quest.boss.hp }}
|
||||
|
||||
dt(:class="smallVersion ? 'col-3' : 'col-4'") {{ $t('difficulty') + ':' }}
|
||||
dd.col-8
|
||||
.svg-icon.inline(
|
||||
v-for="star of stars()", v-html="icons[star]",
|
||||
:class="smallVersion ? 'icon-12' : 'icon-16'",
|
||||
)
|
||||
.table-row
|
||||
dt {{ $t('difficulty') + ':' }}
|
||||
dd
|
||||
.svg-icon.inline(
|
||||
v-for="star of stars()", v-html="icons[star]",
|
||||
:class="smallVersion ? 'icon-12' : 'icon-16'",
|
||||
)
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.row {
|
||||
display: table;
|
||||
color: #E1E0E3;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.table-row {
|
||||
display: table-row;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
dd {
|
||||
height: 24px;
|
||||
padding-left: 1em;
|
||||
padding-top: 3px;
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
|
||||
dt, dd {
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
dt, dd, dd > * {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-size: 1.3em;
|
||||
line-height: 1.2;
|
||||
color: $gray-50;
|
||||
}
|
||||
|
||||
.col-8 {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.col-8:not(:last-child) {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.svg-icon {
|
||||
margin-right: 4px;
|
||||
}
|
||||
@@ -58,6 +77,15 @@ dt {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
// making sure the star-colors always correct
|
||||
.star {
|
||||
fill: #ffb445;
|
||||
}
|
||||
.star-empty {
|
||||
fill: #686274;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -437,7 +437,7 @@
|
||||
|
||||
_forEach(equipmentList, (value) => {
|
||||
this.$set(this.viewOptions, value.key, {
|
||||
selected: true,
|
||||
selected: false,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -446,6 +446,10 @@
|
||||
return [];
|
||||
}
|
||||
},
|
||||
|
||||
anyFilterSelected () {
|
||||
return Object.values(this.viewOptions).some(g => g.selected);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getClassName (classType) {
|
||||
@@ -468,7 +472,7 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
if (viewOptions[i.type] && !viewOptions[i.type].selected) {
|
||||
if (this.anyFilterSelected && viewOptions[i.type] && !viewOptions[i.type].selected) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
div(
|
||||
v-for="category in categories",
|
||||
v-if="!closed && viewOptions[category.identifier].selected",
|
||||
v-if="!anyFilterSelected || (!closed && viewOptions[category.identifier].selected)",
|
||||
:class="category.identifier"
|
||||
)
|
||||
h2.mb-3 {{ category.text }}
|
||||
@@ -329,12 +329,15 @@
|
||||
|
||||
normalGroups.map((category) => {
|
||||
this.$set(this.viewOptions, category.identifier, {
|
||||
selected: true,
|
||||
selected: false,
|
||||
});
|
||||
});
|
||||
|
||||
return normalGroups;
|
||||
},
|
||||
anyFilterSelected () {
|
||||
return Object.values(this.viewOptions).some(g => g.selected);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
travelersItems (category, sortBy, searchBy, hidePinned) {
|
||||
|
||||
@@ -37,8 +37,9 @@
|
||||
draggable.sortable-tasks(
|
||||
ref="tasksList",
|
||||
@update='taskSorted',
|
||||
@start="isDragging(true)",
|
||||
@end="isDragging(false)",
|
||||
:options='{disabled: activeFilter.label === "scheduled", scrollSensitivity: 64}',
|
||||
class="sortable-tasks"
|
||||
)
|
||||
task(
|
||||
v-for="task in taskList",
|
||||
@@ -49,12 +50,11 @@
|
||||
:group='group',
|
||||
)
|
||||
template(v-if="hasRewardsList")
|
||||
draggable(
|
||||
draggable.reward-items(
|
||||
ref="rewardsList",
|
||||
@update="rewardSorted",
|
||||
@start="rewardDragStart",
|
||||
@end="rewardDragEnd",
|
||||
class="reward-items",
|
||||
)
|
||||
shopItem(
|
||||
v-for="reward in inAppRewards",
|
||||
@@ -76,6 +76,9 @@
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
/deep/ .draggable-cursor {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.tasks-column {
|
||||
min-height: 556px;
|
||||
@@ -89,7 +92,6 @@
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
|
||||
.reward-items {
|
||||
@supports (display: grid) {
|
||||
display: grid;
|
||||
@@ -335,6 +337,7 @@ export default {
|
||||
showPopovers: true,
|
||||
|
||||
selectedItemToBuy: {},
|
||||
dragging: false,
|
||||
};
|
||||
},
|
||||
created () {
|
||||
@@ -521,9 +524,11 @@ export default {
|
||||
rewardDragStart () {
|
||||
// We need to stop popovers from interfering with our dragging
|
||||
this.showPopovers = false;
|
||||
this.isDragging(true);
|
||||
},
|
||||
rewardDragEnd () {
|
||||
this.showPopovers = true;
|
||||
this.isDragging(false);
|
||||
},
|
||||
quickAdd (ev) {
|
||||
// Add a new line if Shift+Enter Pressed
|
||||
@@ -678,6 +683,14 @@ export default {
|
||||
this.error(e.message);
|
||||
}
|
||||
},
|
||||
isDragging (dragging) {
|
||||
this.dragging = dragging;
|
||||
if (dragging) {
|
||||
document.documentElement.classList.add('draggable-cursor');
|
||||
} else {
|
||||
document.documentElement.classList.remove('draggable-cursor');
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
v-if="isUser && !isRunningYesterdailies",
|
||||
:right="task.type === 'reward'",
|
||||
ref="taskDropdown",
|
||||
v-b-tooltip.hover.top="$t('showMore')"
|
||||
v-b-tooltip.hover.top="$t('options')"
|
||||
)
|
||||
div(slot="dropdown-toggle", draggable=false)
|
||||
.svg-icon.dropdown-icon(v-html="icons.menu")
|
||||
@@ -46,7 +46,7 @@
|
||||
v-markdown="task.notes",
|
||||
:class="{'has-checklist': task.notes && hasChecklist}",
|
||||
)
|
||||
.checklist(v-if="canViewchecklist")
|
||||
.checklist(v-if="canViewchecklist", :class="{isOpen: !task.collapseChecklist}")
|
||||
.d-inline-flex
|
||||
.collapse-checklist.d-flex.align-items-center.expand-toggle(
|
||||
v-if="isUser",
|
||||
@@ -141,6 +141,11 @@
|
||||
min-width: 0px;
|
||||
overflow-wrap: break-word;
|
||||
|
||||
// markdown p-tag, can't find without /deep/
|
||||
/deep/ p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&.has-notes {
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
@@ -229,7 +234,7 @@
|
||||
overflow-wrap: break-word;
|
||||
|
||||
&.has-checklist {
|
||||
padding-bottom: 8px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,19 +259,25 @@
|
||||
}
|
||||
|
||||
.checklist {
|
||||
margin-bottom: 2px;
|
||||
&.isOpen {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
margin-top: -3px;
|
||||
}
|
||||
|
||||
.collapse-checklist {
|
||||
padding: 2px 6px;
|
||||
margin-bottom: 9px;
|
||||
border-radius: 1px;
|
||||
background-color: $gray-600;
|
||||
font-size: 10px;
|
||||
line-height: 1.2;
|
||||
text-align: center;
|
||||
color: $gray-200;
|
||||
margin-bottom: 9px;
|
||||
|
||||
&.open {
|
||||
}
|
||||
|
||||
span {
|
||||
margin: 0px 4px;
|
||||
@@ -285,7 +296,7 @@
|
||||
margin-bottom: -3px;
|
||||
min-height: 0px;
|
||||
width: 100%;
|
||||
margin-left: 8px;
|
||||
margin-left: 0;
|
||||
padding-right: 20px;
|
||||
overflow-wrap: break-word;
|
||||
|
||||
@@ -427,7 +438,7 @@
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
.task-control, .reward-control {
|
||||
.task-control:not(.task-disabled-habit-control-inner), .reward-control {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,8 @@
|
||||
:clearButtonText='$t("clear")',
|
||||
:todayButton='!challengeAccessRequired',
|
||||
:todayButtonText='$t("today")',
|
||||
:disabled-picker='challengeAccessRequired'
|
||||
:disabled-picker='challengeAccessRequired',
|
||||
:highlighted='calendarHighlights'
|
||||
)
|
||||
.option(v-if="task.type === 'daily'")
|
||||
.form-group
|
||||
@@ -99,7 +100,8 @@
|
||||
:clearButton="false",
|
||||
:todayButton="!challengeAccessRequired",
|
||||
:todayButtonText="$t('today')",
|
||||
:disabled-picker="challengeAccessRequired"
|
||||
:disabled-picker="challengeAccessRequired",
|
||||
:highlighted='calendarHighlights'
|
||||
)
|
||||
.option(v-if="task.type === 'daily'")
|
||||
.form-group
|
||||
@@ -259,6 +261,10 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.input-group > * {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
input, textarea {
|
||||
border: none;
|
||||
background: rgba(0, 0, 0, 0.24);
|
||||
@@ -717,6 +723,7 @@ export default {
|
||||
con: 'constitution',
|
||||
per: 'perception',
|
||||
},
|
||||
calendarHighlights: { dates: [new Date()]},
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
.col-12.col-md-4.offset-md-4
|
||||
.d-flex
|
||||
input.form-control.input-search(type="text", :placeholder="$t('search')", v-model="searchText")
|
||||
button.btn.btn-secondary.dropdown-toggle.ml-2.d-flex.align-items-center(
|
||||
button.btn.btn-secondary.dropdown-toggle.ml-2.d-flex.align-items-center.search-button(
|
||||
type="button",
|
||||
@click="toggleFilterPanel()",
|
||||
:class="{active: selectedTags.length > 0}",
|
||||
@@ -110,6 +110,10 @@
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
.input-search, .search-button {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.tasks-navigation {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ span.badge.badge-pill.badge-item.badge-count(
|
||||
min-width: 24px;
|
||||
height: 24px;
|
||||
box-shadow: 0 1px 1px 0 rgba($black, 0.12);
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
<template lang="pug">
|
||||
.progress-container(ref="container", :id="elementId", :class="{condensed}")
|
||||
.svg-icon(v-html="icon")
|
||||
.progress
|
||||
.progress-bar(:class="progressClass", :style="{width: `${percent(value, maxValue)}%`}")
|
||||
span.small-text {{value | statFloor}} / {{maxValue}}
|
||||
b-tooltip.myClass(:target="() => $refs.container", :container="elementId", :title="tooltip", triggers="hover", placement="bottom")
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~client/assets/scss/colors.scss';
|
||||
|
||||
.progress-container {
|
||||
margin-left: 4px;
|
||||
margin-bottom: .5em;
|
||||
height: 24px;
|
||||
|
||||
/deep/ .bs-tooltip-bottom {
|
||||
top: -16px !important
|
||||
}
|
||||
}
|
||||
|
||||
.progress-container > span {
|
||||
color: $header-color;
|
||||
margin-left: 8px;
|
||||
font-style: normal;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.progress-container > .svg-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.progress-container > .progress {
|
||||
min-width: 200px;
|
||||
margin: 0px;
|
||||
border-radius: 1px;
|
||||
height: 12px;
|
||||
background-color: $header-dark-background;
|
||||
}
|
||||
|
||||
.progress-container > .progress > .progress-bar {
|
||||
border-radius: 1px;
|
||||
height: 12px;
|
||||
min-width: 0px;
|
||||
}
|
||||
|
||||
.progress-container .svg-icon, .progress-container .progress, .progress-container .small-text {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.progress-container.condensed {
|
||||
> .svg-icon {
|
||||
width: 19px;
|
||||
height: 19px;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
> .progress {
|
||||
width: 152px;
|
||||
border-radius: 1px;
|
||||
height: 10px;
|
||||
margin-top: 2px;
|
||||
background: $purple-100;
|
||||
}
|
||||
|
||||
> .progress > .progress-bar {
|
||||
border-radius: 1px;
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import percent from '../../../common/script/libs/percent';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
icon: {
|
||||
type: String,
|
||||
},
|
||||
value: {
|
||||
type: Number,
|
||||
},
|
||||
maxValue: {
|
||||
type: Number,
|
||||
},
|
||||
tooltip: {
|
||||
type: String,
|
||||
},
|
||||
progressClass: {
|
||||
type: String,
|
||||
},
|
||||
condensed: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
elementId: null,
|
||||
};
|
||||
},
|
||||
filters: {
|
||||
statFloor (value) {
|
||||
if (value < 1 && value > 0) {
|
||||
return Math.ceil(value * 10) / 10;
|
||||
} else {
|
||||
return Math.floor(value);
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
percent,
|
||||
click () {
|
||||
this.$emit('click');
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.elementId = `container_${this._uid}`;
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -324,6 +324,7 @@
|
||||
}
|
||||
|
||||
.progress-container > .progress {
|
||||
border-radius: 1px;
|
||||
background-color: $gray-500;
|
||||
}
|
||||
}
|
||||
@@ -371,8 +372,10 @@
|
||||
|
||||
.progress {
|
||||
height: 8px;
|
||||
border-radius: 1px;
|
||||
|
||||
.progress-bar {
|
||||
border-radius: 1px;
|
||||
background-color: $green-10 !important;
|
||||
}
|
||||
}
|
||||
@@ -495,6 +498,9 @@ export default {
|
||||
async userId () {
|
||||
this.loadUser();
|
||||
},
|
||||
userLoggedIn () {
|
||||
this.loadUser();
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async loadUser () {
|
||||
|
||||
@@ -123,8 +123,8 @@
|
||||
h3(v-if='userLevel100Plus', v-once, v-html="$t('noMoreAllocate')")
|
||||
h3
|
||||
| {{$t('statPoints')}}
|
||||
.counter.badge(v-if='user.stats.points || userLevel100Plus')
|
||||
| {{pointsRemaining}}
|
||||
.counter.badge.badge-pill(v-if='user.stats.points || userLevel100Plus')
|
||||
| {{pointsRemaining}}
|
||||
.col-12.col-md-6
|
||||
.float-right
|
||||
toggle-switch(
|
||||
@@ -409,9 +409,6 @@
|
||||
color: #fff;
|
||||
background-color: #ff944c;
|
||||
box-shadow: 0 1px 1px 0 rgba(26, 24, 29, 0.12);
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.box {
|
||||
|
||||
@@ -223,7 +223,6 @@ export default {
|
||||
return true;
|
||||
},
|
||||
amazonPaymentsInit (data) {
|
||||
if (!this.checkGemAmount(data)) return;
|
||||
if (data.type !== 'single' && data.type !== 'subscription') return;
|
||||
|
||||
if (data.gift) {
|
||||
@@ -251,8 +250,30 @@ export default {
|
||||
|
||||
this.amazonPayments.gift = data.gift;
|
||||
this.amazonPayments.type = data.type;
|
||||
},
|
||||
amazonOnError (error) {
|
||||
alert(error.getErrorMessage());
|
||||
this.reset();
|
||||
},
|
||||
reset () {
|
||||
// @TODO: Ensure we are using all of these
|
||||
// some vars are set in the payments mixin. We should try to edit in one place
|
||||
this.amazonPayments.modal = null;
|
||||
this.amazonPayments.type = null;
|
||||
this.amazonPayments.loggedIn = false;
|
||||
|
||||
this.$root.$emit('habitica::pay-with-amazon', this.amazonPayments);
|
||||
// Gift
|
||||
this.amazonPayments.gift = null;
|
||||
this.amazonPayments.giftReceiver = null;
|
||||
|
||||
this.amazonPayments.billingAgreementId = null;
|
||||
this.amazonPayments.orderReferenceId = null;
|
||||
this.amazonPayments.paymentSelected = false;
|
||||
this.amazonPayments.recurringConsent = false;
|
||||
this.amazonPayments.subscription = null;
|
||||
this.amazonPayments.coupon = null;
|
||||
this.amazonPayments.groupToCreate = null;
|
||||
this.amazonPayments.group = null;
|
||||
},
|
||||
async cancelSubscription (config) {
|
||||
if (config && config.group && !confirm(this.$t('confirmCancelGroupPlan'))) return;
|
||||
|
||||
@@ -48,10 +48,18 @@ export async function like (store, payload) {
|
||||
}
|
||||
|
||||
export async function flag (store, payload) {
|
||||
const url = `/api/v4/groups/${payload.groupId}/chat/${payload.chatId}/flag`;
|
||||
let url = '';
|
||||
|
||||
if (payload.groupId === 'privateMessage') {
|
||||
url = `/api/v4/members/flag-private-message/${payload.chatId}`;
|
||||
} else {
|
||||
url = `/api/v4/groups/${payload.groupId}/chat/${payload.chatId}/flag`;
|
||||
}
|
||||
|
||||
const response = await axios.post(url, {
|
||||
comment: payload.comment,
|
||||
});
|
||||
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
|
||||