mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-15 05:37:22 +01:00
lint common
This commit is contained in:
6
package-lock.json
generated
6
package-lock.json
generated
@@ -4476,9 +4476,9 @@
|
||||
}
|
||||
},
|
||||
"eslint-config-habitrpg": {
|
||||
"version": "6.0.7",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-habitrpg/-/eslint-config-habitrpg-6.0.7.tgz",
|
||||
"integrity": "sha512-hda2IKsfwE/94CjLtPI3Cgsq0capQCFKCiqPPNM7foeO/E6cZpXCSvMHdGt5TXy66DQxF5h+kz4xcheHdcaRcA==",
|
||||
"version": "6.0.8",
|
||||
"resolved": "https://registry.npmjs.org/eslint-config-habitrpg/-/eslint-config-habitrpg-6.0.8.tgz",
|
||||
"integrity": "sha512-jQ62H3+Gkie4CK8uFfV37SX+yNs6yu+SHP27hIYIlnZ21HCaQnabEQfhrYzbpQUn9fNd2y1gUNqGOIG8ph84vg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eslint": "^6.5.1",
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
"npm": "^6"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint --ext .js --fix ./website/server",
|
||||
"lint": "eslint --ext .js --fix ./website/common",
|
||||
"test": "npm run lint && gulp test && gulp apidoc",
|
||||
"test:build": "gulp test:prepare:build",
|
||||
"test:api-v3": "gulp test:api-v3",
|
||||
@@ -103,7 +103,7 @@
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"chalk": "^2.4.1",
|
||||
"eslint": "^6.5.1",
|
||||
"eslint-config-habitrpg": "^6.0.7",
|
||||
"eslint-config-habitrpg": "^6.0.8",
|
||||
"eslint-plugin-mocha": "^5.0.0",
|
||||
"expect.js": "^0.3.1",
|
||||
"istanbul": "^1.1.0-alpha.1",
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
/* global env:true, rm:true, mkdir:true, cp:true */
|
||||
|
||||
// https://github.com/shelljs/shelljs
|
||||
require('shelljs/global');
|
||||
|
||||
const path = require('path');
|
||||
const config = require('./config');
|
||||
const ora = require('ora');
|
||||
const webpack = require('webpack');
|
||||
const webpackConfig = require('./webpack.prod.conf');
|
||||
|
||||
module.exports = function webpackProductionBuild (callback) {
|
||||
env.NODE_ENV = 'production';
|
||||
|
||||
console.log( // eslint-disable-line no-console
|
||||
' Tip:\n' +
|
||||
' Built files are meant to be served over an HTTP server.\n' +
|
||||
' Opening index.html over file:// won\'t work.\n'
|
||||
);
|
||||
|
||||
const spinner = ora('building for production...');
|
||||
spinner.start();
|
||||
|
||||
const assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory);
|
||||
rm('-rf', assetsPath);
|
||||
mkdir('-p', assetsPath);
|
||||
cp('-R', config.build.staticAssetsDirectory, assetsPath);
|
||||
|
||||
webpack(webpackConfig, (err, stats) => {
|
||||
spinner.stop();
|
||||
|
||||
const output = `${stats.toString({
|
||||
colors: true,
|
||||
modules: false,
|
||||
children: false,
|
||||
chunks: false,
|
||||
chunkModules: false,
|
||||
})}\n`;
|
||||
|
||||
if (callback) {
|
||||
return err ? callback(err) : callback(null, output);
|
||||
} else {
|
||||
if (err) throw err;
|
||||
process.stdout.write(output);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -1,6 +0,0 @@
|
||||
const merge = require('webpack-merge');
|
||||
const prodEnv = require('./prod.env');
|
||||
|
||||
module.exports = merge(prodEnv, {
|
||||
NODE_ENV: '"development"',
|
||||
});
|
||||
@@ -1,81 +0,0 @@
|
||||
// see http://vuejs-templates.github.io/webpack for documentation.
|
||||
const path = require('path');
|
||||
const staticAssetsDirectory = './website/static/.'; // The folder where static files (not processed) live
|
||||
const prodEnv = require('./prod.env');
|
||||
const devEnv = require('./dev.env');
|
||||
const nconf = require('nconf');
|
||||
const setupNconf = require('../../website/server/libs/setupNconf');
|
||||
|
||||
let configFile = path.join(path.resolve(__dirname, '../../config.json'));
|
||||
|
||||
setupNconf(configFile);
|
||||
|
||||
const DEV_BASE_URL = nconf.get('BASE_URL');
|
||||
|
||||
module.exports = {
|
||||
build: {
|
||||
env: prodEnv,
|
||||
index: path.resolve(__dirname, '../../dist-client/index.html'),
|
||||
assetsRoot: path.resolve(__dirname, '../../dist-client'),
|
||||
assetsSubDirectory: 'static',
|
||||
assetsPublicPath: '/',
|
||||
staticAssetsDirectory,
|
||||
productionSourceMap: true,
|
||||
// Gzip off by default as many popular static hosts such as
|
||||
// Surge or Netlify already gzip all static assets for you.
|
||||
// Before setting to `true`, make sure to:
|
||||
// npm install --save-dev compression-webpack-plugin
|
||||
productionGzip: false,
|
||||
productionGzipExtensions: ['js', 'css'],
|
||||
// Run the build command with an extra argument to
|
||||
// View the bundle analyzer report after build finishes:
|
||||
// `npm run client:build --report`
|
||||
// Set to `true` or `false` to always turn it on or off
|
||||
bundleAnalyzerReport: process.env.npm_config_report, // eslint-disable-line no-process-env
|
||||
},
|
||||
dev: {
|
||||
env: devEnv,
|
||||
port: 8080,
|
||||
autoOpenBrowser: true,
|
||||
assetsSubDirectory: 'static',
|
||||
assetsPublicPath: '/',
|
||||
staticAssetsDirectory,
|
||||
proxyTable: {
|
||||
// proxy all requests to the server at IP:PORT as specified in the top-level config
|
||||
'/api/v3': {
|
||||
target: DEV_BASE_URL,
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/api/v4': {
|
||||
target: DEV_BASE_URL,
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/stripe': {
|
||||
target: DEV_BASE_URL,
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/amazon': {
|
||||
target: DEV_BASE_URL,
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/paypal': {
|
||||
target: DEV_BASE_URL,
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/logout-server': {
|
||||
target: DEV_BASE_URL,
|
||||
changeOrigin: true,
|
||||
},
|
||||
'/export': {
|
||||
target: DEV_BASE_URL,
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
// CSS Sourcemaps off by default because relative paths are "buggy"
|
||||
// with this option, according to the CSS-Loader README
|
||||
// (https://github.com/webpack/css-loader#sourcemaps)
|
||||
// In our experience, they generally work as expected,
|
||||
// just be aware of this issue when enabling this option.
|
||||
cssSourceMap: false,
|
||||
},
|
||||
};
|
||||
@@ -1,45 +0,0 @@
|
||||
const nconf = require('nconf');
|
||||
const { join, resolve } = require('path');
|
||||
const setupNconf = require('../../website/server/libs/setupNconf');
|
||||
|
||||
const PATH_TO_CONFIG = join(resolve(__dirname, '../../config.json'));
|
||||
let configFile = PATH_TO_CONFIG;
|
||||
|
||||
setupNconf(configFile);
|
||||
|
||||
// @TODO: Check if we can import from client. Items like admin emails can be imported
|
||||
// and that should be prefered
|
||||
|
||||
// To avoid stringifying more data then we need,
|
||||
// items from `env` used on the client will have to be specified in this array
|
||||
// @TODO: Do we need? const CLIENT_VARS = ['language', 'isStaticPage', 'availableLanguages', 'translations',
|
||||
// 'FACEBOOK_KEY', 'GOOGLE_CLIENT_ID', 'NODE_ENV', 'BASE_URL', 'GA_ID',
|
||||
// 'AMAZON_PAYMENTS', 'STRIPE_PUB_KEY', 'AMPLITUDE_KEY',
|
||||
// 'worldDmg', 'mods', 'IS_MOBILE'];
|
||||
|
||||
const AMAZON_SELLER_ID = nconf.get('AMAZON_PAYMENTS_SELLER_ID');
|
||||
const AMAZON_CLIENT_ID = nconf.get('AMAZON_PAYMENTS_CLIENT_ID');
|
||||
const AMAZON_MODE = nconf.get('AMAZON_PAYMENTS_MODE');
|
||||
|
||||
let env = {
|
||||
NODE_ENV: '"production"',
|
||||
// clientVars: CLIENT_VARS,
|
||||
AMAZON_PAYMENTS: {
|
||||
SELLER_ID: `"${AMAZON_SELLER_ID}"`,
|
||||
CLIENT_ID: `"${AMAZON_CLIENT_ID}"`,
|
||||
MODE: `"${AMAZON_MODE}"`,
|
||||
},
|
||||
EMAILS: {
|
||||
COMMUNITY_MANAGER_EMAIL: `"${nconf.get('EMAILS_COMMUNITY_MANAGER_EMAIL')}"`,
|
||||
TECH_ASSISTANCE_EMAIL: `"${nconf.get('EMAILS_TECH_ASSISTANCE_EMAIL')}"`,
|
||||
PRESS_ENQUIRY_EMAIL: `"${nconf.get('EMAILS_PRESS_ENQUIRY_EMAIL')}"`,
|
||||
},
|
||||
};
|
||||
|
||||
'NODE_ENV BASE_URL GA_ID STRIPE_PUB_KEY FACEBOOK_KEY GOOGLE_CLIENT_ID AMPLITUDE_KEY LOGGLY_CLIENT_TOKEN'
|
||||
.split(' ')
|
||||
.forEach(key => {
|
||||
env[key] = `"${nconf.get(key)}"`;
|
||||
});
|
||||
|
||||
module.exports = env;
|
||||
@@ -1,6 +0,0 @@
|
||||
const merge = require('webpack-merge');
|
||||
const devEnv = require('./dev.env');
|
||||
|
||||
module.exports = merge(devEnv, {
|
||||
NODE_ENV: '"test"',
|
||||
});
|
||||
@@ -1,10 +0,0 @@
|
||||
/* global window:true */
|
||||
|
||||
require('eventsource-polyfill');
|
||||
const hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true&overlay=false');
|
||||
|
||||
hotClient.subscribe(event => {
|
||||
if (event.action === 'reload') {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
@@ -1,72 +0,0 @@
|
||||
/* eslint-disable no-process-env, no-console */
|
||||
|
||||
const path = require('path');
|
||||
const express = require('express');
|
||||
const webpack = require('webpack');
|
||||
const config = require('./config');
|
||||
|
||||
if (!process.env.NODE_ENV) {
|
||||
process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV);
|
||||
}
|
||||
|
||||
const proxyMiddleware = require('http-proxy-middleware');
|
||||
const webpackConfig = process.env.NODE_ENV === 'test' ?
|
||||
require('./webpack.prod.conf') :
|
||||
require('./webpack.dev.conf');
|
||||
|
||||
// default port where dev server listens for incoming traffic
|
||||
const port = process.env.PORT || config.dev.port;
|
||||
// Define HTTP proxies to your custom API backend
|
||||
// https://github.com/chimurai/http-proxy-middleware
|
||||
const proxyTable = config.dev.proxyTable;
|
||||
|
||||
const app = express();
|
||||
const compiler = webpack(webpackConfig);
|
||||
|
||||
const devMiddleware = require('webpack-dev-middleware')(compiler, {
|
||||
publicPath: webpackConfig.output.publicPath,
|
||||
stats: {
|
||||
colors: true,
|
||||
chunks: false,
|
||||
},
|
||||
});
|
||||
|
||||
const hotMiddleware = require('webpack-hot-middleware')(compiler);
|
||||
// force page reload when html-webpack-plugin template changes
|
||||
compiler.plugin('compilation', (compilation) => {
|
||||
compilation.plugin('html-webpack-plugin-after-emit', (data, cb) => {
|
||||
hotMiddleware.publish({ action: 'reload' });
|
||||
cb();
|
||||
});
|
||||
});
|
||||
|
||||
// proxy api requests
|
||||
Object.keys(proxyTable).forEach((context) => {
|
||||
let options = proxyTable[context];
|
||||
if (typeof options === 'string') {
|
||||
options = { target: options };
|
||||
}
|
||||
app.use(proxyMiddleware(options.filter || context, options));
|
||||
});
|
||||
|
||||
// handle fallback for HTML5 history API
|
||||
app.use(require('connect-history-api-fallback')());
|
||||
|
||||
// serve webpack bundle output
|
||||
app.use(devMiddleware);
|
||||
|
||||
// enable hot-reload and state-preserving
|
||||
// compilation error display
|
||||
app.use(hotMiddleware);
|
||||
|
||||
// serve pure static assets
|
||||
const staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory);
|
||||
app.use(staticPath, express.static(config.dev.staticAssetsDirectory));
|
||||
|
||||
module.exports = app.listen(port, (err) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
console.log(`Listening at http://localhost:${port}\n`);
|
||||
});
|
||||
@@ -1,66 +0,0 @@
|
||||
/* eslint-disable no-process-env, no-console */
|
||||
|
||||
const path = require('path');
|
||||
const config = require('./config');
|
||||
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||
|
||||
exports.assetsPath = (_path) => {
|
||||
const assetsSubDirectory = process.env.NODE_ENV === 'production' ?
|
||||
config.build.assetsSubDirectory :
|
||||
config.dev.assetsSubDirectory;
|
||||
return path.posix.join(assetsSubDirectory, _path);
|
||||
};
|
||||
|
||||
exports.cssLoaders = function cssLoaders (options) {
|
||||
options = options || {};
|
||||
// generate loader string to be used with extract text plugin
|
||||
function generateLoaders (loaders) {
|
||||
let sourceLoader = loaders.map((loader) => {
|
||||
let extraParamChar;
|
||||
if (/\?/.test(loader)) {
|
||||
loader = loader.replace(/\?/, '-loader?');
|
||||
extraParamChar = '&';
|
||||
} else {
|
||||
loader = `${loader}-loader`;
|
||||
extraParamChar = '?';
|
||||
}
|
||||
return loader + (options.sourceMap ? `${extraParamChar}sourceMap` : '');
|
||||
}).join('!');
|
||||
|
||||
// Extract CSS when that option is specified
|
||||
// (which is the case during production build)
|
||||
if (options.extract) {
|
||||
return ExtractTextPlugin.extract({
|
||||
use: sourceLoader,
|
||||
fallback: 'vue-style-loader',
|
||||
});
|
||||
} else {
|
||||
return ['vue-style-loader', sourceLoader].join('!');
|
||||
}
|
||||
}
|
||||
|
||||
// http://vuejs.github.io/vue-loader/en/configurations/extract-css.html
|
||||
return {
|
||||
css: generateLoaders(['css']),
|
||||
postcss: generateLoaders(['css']),
|
||||
less: generateLoaders(['css', 'less']),
|
||||
sass: generateLoaders(['css', 'sass?indentedSyntax']),
|
||||
scss: generateLoaders(['css', 'sass']),
|
||||
stylus: generateLoaders(['css', 'stylus']),
|
||||
styl: generateLoaders(['css', 'stylus']),
|
||||
};
|
||||
};
|
||||
|
||||
// Generate loaders for standalone style files (outside of .vue)
|
||||
exports.styleLoaders = (options) => {
|
||||
const output = [];
|
||||
const loaders = exports.cssLoaders(options);
|
||||
for (let extension in loaders) {
|
||||
const loader = loaders[extension];
|
||||
output.push({
|
||||
test: new RegExp(`\\.${extension}$`),
|
||||
loader,
|
||||
});
|
||||
}
|
||||
return output;
|
||||
};
|
||||
@@ -1,154 +0,0 @@
|
||||
/* eslint-disable no-process-env, no-console */
|
||||
|
||||
const path = require('path');
|
||||
const config = require('./config');
|
||||
const utils = require('./utils');
|
||||
const webpack = require('webpack');
|
||||
const projectRoot = path.resolve(__dirname, '../');
|
||||
const autoprefixer = require('autoprefixer');
|
||||
const postcssEasyImport = require('postcss-easy-import');
|
||||
const IS_PROD = process.env.NODE_ENV === 'production';
|
||||
|
||||
const baseConfig = {
|
||||
entry: {
|
||||
app: ['babel-polyfill', './website/client/main.js'],
|
||||
},
|
||||
output: {
|
||||
path: config.build.assetsRoot,
|
||||
publicPath: IS_PROD ? config.build.assetsPublicPath : config.dev.assetsPublicPath,
|
||||
filename: '[name].js',
|
||||
devtoolModuleFilenameTemplate (info) {
|
||||
// Fix source maps, code from
|
||||
// https://github.com/Darkside73/bbsmile.com.ua/commit/3596d3c42ef91b69d8380359c3e8908edc08acdb
|
||||
let filename = info.resourcePath;
|
||||
if (info.resource.match(/\.vue$/) && !info.allLoaders.match(/type=script/)) {
|
||||
filename = 'generated';
|
||||
}
|
||||
|
||||
return filename;
|
||||
},
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['*', '.js', '.vue', '.json'],
|
||||
modules: [
|
||||
path.join(projectRoot, 'website'),
|
||||
path.join(projectRoot, 'test/client/unit'),
|
||||
path.join(projectRoot, 'node_modules'),
|
||||
],
|
||||
alias: {
|
||||
website: path.resolve(projectRoot, 'website'),
|
||||
common: path.resolve(projectRoot, 'website/common'),
|
||||
client: path.resolve(projectRoot, 'website/client'),
|
||||
assets: path.resolve(projectRoot, 'website/client/assets'),
|
||||
components: path.resolve(projectRoot, 'website/client/components'),
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
new webpack.ContextReplacementPlugin(/moment[\\\/]locale$/, /^\.\/(NOT_EXISTING)$/),
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.vue$/,
|
||||
loader: 'vue-loader',
|
||||
options: {
|
||||
loaders: utils.cssLoaders({
|
||||
sourceMap: IS_PROD ?
|
||||
config.build.productionSourceMap :
|
||||
config.dev.cssSourceMap,
|
||||
extract: IS_PROD,
|
||||
}),
|
||||
postcss: [
|
||||
autoprefixer({
|
||||
overrideBrowserslist: ['last 2 versions'],
|
||||
}),
|
||||
postcssEasyImport(),
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel-loader',
|
||||
include: [
|
||||
path.join(projectRoot, 'test'),
|
||||
path.join(projectRoot, 'website'),
|
||||
path.join(projectRoot, 'node_modules', 'bootstrap-vue'),
|
||||
],
|
||||
options: {
|
||||
cacheDirectory: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif)(\?.*)?$/,
|
||||
loader: 'url-loader',
|
||||
query: {
|
||||
limit: 10000,
|
||||
name: utils.assetsPath('images/[name].[hash:7].[ext]'),
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
||||
loader: 'url-loader',
|
||||
query: {
|
||||
limit: 10000,
|
||||
name: utils.assetsPath('fonts/[name].[hash:7].[ext]'),
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.svg$/,
|
||||
use: [
|
||||
{ loader: 'svg-inline-loader' },
|
||||
{
|
||||
loader: 'svgo-loader',
|
||||
options: {
|
||||
plugins: [
|
||||
{removeViewBox: false},
|
||||
{convertPathData: {noSpaceAfterFlags: false}},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
exclude: [path.resolve(projectRoot, 'website/client/assets/svg/for-css')],
|
||||
},
|
||||
{
|
||||
test: /\.svg$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'svg-url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: utils.assetsPath('svg/[name].[hash:7].[ext]'),
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: 'svgo-loader',
|
||||
options: {
|
||||
plugins: [
|
||||
{removeViewBox: false},
|
||||
{convertPathData: {noSpaceAfterFlags: false}},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
include: [path.resolve(projectRoot, 'website/client/assets/svg/for-css')],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
if (!IS_PROD) {
|
||||
const eslintFriendlyFormatter = require('eslint-friendly-formatter'); // eslint-disable-line global-require
|
||||
|
||||
baseConfig.module.rules.unshift({
|
||||
test: /\.(js|vue)$/,
|
||||
loader: 'eslint-loader',
|
||||
enforce: 'pre',
|
||||
include: projectRoot,
|
||||
options: {
|
||||
formatter: eslintFriendlyFormatter,
|
||||
emitWarning: true,
|
||||
},
|
||||
exclude: /node_modules/,
|
||||
});
|
||||
}
|
||||
module.exports = baseConfig;
|
||||
@@ -1,32 +0,0 @@
|
||||
const config = require('./config');
|
||||
const webpack = require('webpack');
|
||||
const merge = require('webpack-merge');
|
||||
const utils = require('./utils');
|
||||
const baseWebpackConfig = require('./webpack.base.conf');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
|
||||
// add hot-reload related code to entry chunks
|
||||
Object.keys(baseWebpackConfig.entry).forEach((name) => {
|
||||
baseWebpackConfig.entry[name] = baseWebpackConfig.entry[name].concat('./webpack/dev-client');
|
||||
});
|
||||
|
||||
module.exports = merge(baseWebpackConfig, {
|
||||
module: {
|
||||
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }),
|
||||
},
|
||||
// cheap-module-eval-source-map is faster for development
|
||||
devtool: '#cheap-module-eval-source-map',
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': config.dev.env,
|
||||
}),
|
||||
// https://github.com/glenjamin/webpack-hot-middleware#installation--usage
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
// https://github.com/ampedandwired/html-webpack-plugin
|
||||
new HtmlWebpackPlugin({
|
||||
filename: 'index.html',
|
||||
template: './website/client/index.html',
|
||||
inject: true,
|
||||
}),
|
||||
],
|
||||
});
|
||||
@@ -1,101 +0,0 @@
|
||||
/* eslint-disable no-process-env, no-console */
|
||||
|
||||
const path = require('path');
|
||||
const config = require('./config');
|
||||
const utils = require('./utils');
|
||||
const webpack = require('webpack');
|
||||
const merge = require('webpack-merge');
|
||||
const baseWebpackConfig = require('./webpack.base.conf');
|
||||
const ExtractTextPlugin = require('extract-text-webpack-plugin');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const env = process.env.NODE_ENV === 'test' ?
|
||||
require('./config/test.env') :
|
||||
config.build.env;
|
||||
|
||||
const webpackConfig = merge(baseWebpackConfig, {
|
||||
module: {
|
||||
rules: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true }),
|
||||
},
|
||||
devtool: config.build.productionSourceMap ? '#source-map' : false,
|
||||
output: {
|
||||
path: config.build.assetsRoot,
|
||||
filename: utils.assetsPath('js/[name].[chunkhash].js'),
|
||||
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js'),
|
||||
},
|
||||
plugins: [
|
||||
// http://vuejs.github.io/vue-loader/workflow/production.html
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': env,
|
||||
}),
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
compress: {
|
||||
warnings: false,
|
||||
},
|
||||
sourceMap: true,
|
||||
}),
|
||||
// extract css into its own file
|
||||
new ExtractTextPlugin({
|
||||
filename: utils.assetsPath('css/[name].[contenthash].css'),
|
||||
}),
|
||||
// generate dist index.html with correct asset hash for caching.
|
||||
// you can customize output by editing /index.html
|
||||
// see https://github.com/ampedandwired/html-webpack-plugin
|
||||
new HtmlWebpackPlugin({
|
||||
filename: process.env.NODE_ENV === 'test' ?
|
||||
'index.html' :
|
||||
config.build.index,
|
||||
template: './website/client/index.html',
|
||||
inject: true,
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeAttributeQuotes: true,
|
||||
// more options:
|
||||
// https://github.com/kangax/html-minifier#options-quick-reference
|
||||
},
|
||||
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
|
||||
chunksSortMode: 'dependency',
|
||||
}),
|
||||
// split vendor js into its own file
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
name: 'vendor',
|
||||
minChunks (scriptModule) {
|
||||
// any required modules inside node_modules are extracted to vendor
|
||||
return (
|
||||
scriptModule.resource &&
|
||||
/\.js$/.test(scriptModule.resource) &&
|
||||
scriptModule.resource.indexOf(
|
||||
path.join(__dirname, '../node_modules')
|
||||
) === 0
|
||||
);
|
||||
},
|
||||
}),
|
||||
// extract webpack runtime and module manifest to its own file in order to
|
||||
// prevent vendor hash from being updated whenever app bundle is updated
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
name: 'manifest',
|
||||
chunks: ['vendor'],
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
if (config.build.productionGzip) {
|
||||
const CompressionWebpackPlugin = require('compression-webpack-plugin'); // eslint-disable-line global-require
|
||||
|
||||
webpackConfig.plugins.push(
|
||||
new CompressionWebpackPlugin({
|
||||
asset: '[path].gz[query]',
|
||||
algorithm: 'gzip',
|
||||
test: new RegExp(`\\.(${config.build.productionGzipExtensions.join('|')})$`),
|
||||
threshold: 10240,
|
||||
minRatio: 0.8,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (config.build.bundleAnalyzerReport) {
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; // eslint-disable-line global-require
|
||||
webpackConfig.plugins.push(new BundleAnalyzerPlugin());
|
||||
}
|
||||
|
||||
module.exports = webpackConfig;
|
||||
@@ -1,24 +0,0 @@
|
||||
// This is the webpack config used for unit tests.
|
||||
const merge = require('webpack-merge');
|
||||
const baseConfig = require('./webpack.base.conf');
|
||||
const utils = require('./utils');
|
||||
const webpack = require('webpack');
|
||||
const testEnv = require('./config/test.env');
|
||||
|
||||
const webpackConfig = merge(baseConfig, {
|
||||
// use inline sourcemap for karma-sourcemap-loader
|
||||
module: {
|
||||
rules: utils.styleLoaders(),
|
||||
},
|
||||
devtool: '#inline-source-map',
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': testEnv,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
// no need for app entry during tests
|
||||
delete webpackConfig.entry;
|
||||
|
||||
module.exports = webpackConfig;
|
||||
@@ -1,27 +1,26 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
node: true
|
||||
node: true,
|
||||
},
|
||||
'extends': [
|
||||
'plugin:vue/essential',
|
||||
'eslint:recommended'
|
||||
extends: [
|
||||
'habitrpg/lib/vue',
|
||||
],
|
||||
rules: {
|
||||
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
|
||||
},
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint'
|
||||
parser: 'babel-eslint',
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: [
|
||||
'**/__tests__/*.{j,t}s?(x)'
|
||||
'**/__tests__/*.{j,t}s?(x)',
|
||||
],
|
||||
env: {
|
||||
mocha: true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
mocha: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/cli-plugin-babel/preset'
|
||||
]
|
||||
}
|
||||
'@vue/cli-plugin-babel/preset',
|
||||
],
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
autoprefixer: {}
|
||||
}
|
||||
}
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -201,8 +201,7 @@ import bannedAccountModal from '@/components/bannedAccountModal';
|
||||
const COMMUNITY_MANAGER_EMAIL = process.env.EMAILS_COMMUNITY_MANAGER_EMAIL; // eslint-disable-line
|
||||
|
||||
export default {
|
||||
mixins: [notifications, spellsMixin],
|
||||
name: 'app',
|
||||
name: 'App',
|
||||
components: {
|
||||
AppMenu,
|
||||
AppHeader,
|
||||
@@ -217,6 +216,7 @@ export default {
|
||||
subCancelModalConfirm,
|
||||
subCanceledModal,
|
||||
},
|
||||
mixins: [notifications, spellsMixin],
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
@@ -237,7 +237,7 @@ export default {
|
||||
...mapState(['isUserLoggedIn', 'browserTimezoneOffset', 'isUserLoaded']),
|
||||
...mapState({ user: 'user.data' }),
|
||||
isStaticPage () {
|
||||
return this.$route.meta.requiresLogin === false ? true : false;
|
||||
return this.$route.meta.requiresLogin === false;
|
||||
},
|
||||
castingSpell () {
|
||||
return this.$store.state.spellOptions.castingSpell;
|
||||
@@ -256,14 +256,14 @@ export default {
|
||||
},
|
||||
},
|
||||
created () {
|
||||
this.$root.$on('playSound', (sound) => {
|
||||
let theme = this.user.preferences.sound;
|
||||
this.$root.$on('playSound', sound => {
|
||||
const theme = this.user.preferences.sound;
|
||||
|
||||
if (!theme || theme === 'off') {
|
||||
return;
|
||||
}
|
||||
|
||||
let file = `/static/audio/${theme}/${sound}`;
|
||||
const file = `/static/audio/${theme}/${sound}`;
|
||||
|
||||
if (this.audioSuffix === null) {
|
||||
this.audioSource = document.createElement('source');
|
||||
@@ -284,12 +284,12 @@ export default {
|
||||
});
|
||||
|
||||
// @TODO: I'm not sure these should be at the app level. Can we move these back into shop/inventory or maybe they need a lateral move?
|
||||
this.$root.$on('buyModal::showItem', (item) => {
|
||||
this.$root.$on('buyModal::showItem', item => {
|
||||
this.selectedItemToBuy = item;
|
||||
this.$root.$emit('bv::show::modal', 'buy-modal');
|
||||
});
|
||||
|
||||
this.$root.$on('selectMembersModal::showItem', (item) => {
|
||||
this.$root.$on('selectMembersModal::showItem', item => {
|
||||
this.selectedSpellToBuy = item;
|
||||
this.$root.$emit('bv::show::modal', 'select-member-modal');
|
||||
});
|
||||
@@ -301,18 +301,18 @@ export default {
|
||||
});
|
||||
|
||||
// Set up Error interceptors
|
||||
axios.interceptors.response.use((response) => {
|
||||
axios.interceptors.response.use(response => {
|
||||
if (this.user && response.data && response.data.notifications) {
|
||||
this.$set(this.user, 'notifications', response.data.notifications);
|
||||
}
|
||||
return response;
|
||||
}, (error) => {
|
||||
}, error => {
|
||||
if (error.response.status >= 400) {
|
||||
this.checkForBannedUser(error);
|
||||
|
||||
// Don't show errors from getting user details. These users have delete their account,
|
||||
// but their chat message still exists.
|
||||
let configExists = Boolean(error.response) && Boolean(error.response.config);
|
||||
const configExists = Boolean(error.response) && Boolean(error.response.config);
|
||||
if (configExists && error.response.config.method === 'get' && error.response.config.url.indexOf('/api/v4/members/') !== -1) {
|
||||
// @TODO: We resolve the promise because we need our caching to cache this user as tried
|
||||
// Chat paging should help this, but maybe we can also find another solution..
|
||||
@@ -333,11 +333,11 @@ export default {
|
||||
let snackbarTimeout = false;
|
||||
if (error.response.status === 502) snackbarTimeout = true;
|
||||
|
||||
let errorsToShow = [];
|
||||
const errorsToShow = [];
|
||||
// show only the first error for each param
|
||||
let paramErrorsFound = {};
|
||||
const paramErrorsFound = {};
|
||||
if (errorData.errors) {
|
||||
for (let e of errorData.errors) {
|
||||
for (const e of errorData.errors) {
|
||||
if (!paramErrorsFound[e.param]) {
|
||||
errorsToShow.push(e.message);
|
||||
paramErrorsFound[e.param] = true;
|
||||
@@ -362,11 +362,11 @@ export default {
|
||||
return Promise.reject(error);
|
||||
});
|
||||
|
||||
axios.interceptors.response.use((response) => {
|
||||
axios.interceptors.response.use(response => {
|
||||
// Verify that the user was not updated from another browser/app/client
|
||||
// If it was, sync
|
||||
const url = response.config.url;
|
||||
const method = response.config.method;
|
||||
const { url } = response.config;
|
||||
const { method } = response.config;
|
||||
|
||||
const isApiCall = url.indexOf('api/v4') !== -1;
|
||||
const userV = response.data && response.data.userV;
|
||||
@@ -407,7 +407,7 @@ export default {
|
||||
});
|
||||
|
||||
// Setup listener for title
|
||||
this.$store.watch(state => state.title, (title) => {
|
||||
this.$store.watch(state => state.title, title => {
|
||||
document.title = title;
|
||||
});
|
||||
this.$nextTick(() => {
|
||||
@@ -446,7 +446,7 @@ export default {
|
||||
// Load external scripts after the app has been rendered
|
||||
setupPayments();
|
||||
});
|
||||
}).catch((err) => {
|
||||
}).catch(err => {
|
||||
console.error('Impossible to fetch user. Clean up localStorage and refresh.', err); // eslint-disable-line no-console
|
||||
});
|
||||
} else {
|
||||
@@ -491,7 +491,7 @@ export default {
|
||||
// Manage modals
|
||||
this.$root.$on('bv::show::modal', (modalId, data = {}) => {
|
||||
if (data.fromRoot) return;
|
||||
const modalStack = this.$store.state.modalStack;
|
||||
const { modalStack } = this.$store.state;
|
||||
|
||||
this.trackGemPurchase(modalId, data);
|
||||
|
||||
@@ -501,7 +501,7 @@ export default {
|
||||
modalStack.push({ modalId, prev: prevId });
|
||||
});
|
||||
|
||||
this.$root.$on('bv::modal::hidden', (bvEvent) => {
|
||||
this.$root.$on('bv::modal::hidden', bvEvent => {
|
||||
let modalId = bvEvent.target && bvEvent.target.id;
|
||||
|
||||
// sometimes the target isn't passed to the hidden event, fallback is the vueTarget
|
||||
@@ -513,7 +513,7 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
const modalStack = this.$store.state.modalStack;
|
||||
const { modalStack } = this.$store.state;
|
||||
|
||||
const modalOnTop = modalStack[modalStack.length - 1];
|
||||
|
||||
@@ -537,7 +537,7 @@ export default {
|
||||
const modalCount = {};
|
||||
const prevAndCurrent = 2;
|
||||
|
||||
for (let index in modalStack) {
|
||||
for (const index in modalStack) {
|
||||
const current = modalStack[index];
|
||||
|
||||
if (!modalCount[current.modalId]) modalCount[current.modalId] = 0;
|
||||
@@ -574,11 +574,9 @@ export default {
|
||||
this.selectedItemToBuy = item;
|
||||
},
|
||||
genericPurchase (item) {
|
||||
if (!item)
|
||||
return false;
|
||||
if (!item) return false;
|
||||
|
||||
if (['card', 'debuffPotion'].includes(item.purchaseType))
|
||||
return false;
|
||||
if (['card', 'debuffPotion'].includes(item.purchaseType)) return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
@@ -17,9 +17,8 @@ export default {
|
||||
contactUsLink () {
|
||||
if (this.isUserLoggedIn) {
|
||||
return { name: 'guild', params: { groupId: 'a29da26b-37de-4a71-b0c6-48e72a900dac' } };
|
||||
} else {
|
||||
return {name: 'contact'};
|
||||
}
|
||||
return { name: 'contact' };
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -56,13 +56,14 @@
|
||||
|
||||
<script>
|
||||
// @TODO:
|
||||
let BASE_URL = 'https://habitica.com';
|
||||
import twitter from '@/assets/svg/twitter.svg';
|
||||
import facebook from '@/assets/svg/facebook.svg';
|
||||
|
||||
const BASE_URL = 'https://habitica.com';
|
||||
|
||||
export default {
|
||||
data () {
|
||||
let tweet = this.$t('achievementShare');
|
||||
const tweet = this.$t('achievementShare');
|
||||
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
|
||||
@@ -136,6 +136,9 @@ export default {
|
||||
classes: 'content.classes',
|
||||
}),
|
||||
},
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
@@ -147,9 +150,6 @@ export default {
|
||||
selectedClass: 'warrior',
|
||||
};
|
||||
},
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
},
|
||||
methods: {
|
||||
close () {
|
||||
this.$root.$emit('bv::hide::modal', 'choose-class');
|
||||
@@ -170,13 +170,13 @@ export default {
|
||||
shield: 'shield_special_fall2019Rogue',
|
||||
weapon: 'weapon_special_fall2019Rogue',
|
||||
};
|
||||
} else if (heroClass === 'wizard') {
|
||||
} if (heroClass === 'wizard') {
|
||||
return {
|
||||
armor: 'armor_special_fall2019Mage',
|
||||
head: 'head_special_fall2019Mage',
|
||||
weapon: 'weapon_special_fall2019Mage',
|
||||
};
|
||||
} else if (heroClass === 'healer') {
|
||||
} if (heroClass === 'healer') {
|
||||
return {
|
||||
armor: 'armor_special_fall2019Healer',
|
||||
eyewear: 'eyewear_special_fall2019Healer',
|
||||
@@ -184,14 +184,13 @@ export default {
|
||||
shield: 'shield_special_fall2019Healer',
|
||||
weapon: 'weapon_special_fall2019Healer',
|
||||
};
|
||||
} else {
|
||||
}
|
||||
return {
|
||||
armor: 'armor_special_fall2019Warrior',
|
||||
head: 'head_special_fall2019Warrior',
|
||||
shield: 'shield_special_fall2019Warrior',
|
||||
weapon: 'weapon_special_fall2019Warrior',
|
||||
};
|
||||
}
|
||||
},
|
||||
selectionBox (selectedClass, heroClass) {
|
||||
if (selectedClass === heroClass) {
|
||||
|
||||
@@ -121,15 +121,15 @@ import styleHelper from '@/mixins/styleHelper';
|
||||
import twitter from '@/assets/svg/twitter.svg';
|
||||
import facebook from '@/assets/svg/facebook.svg';
|
||||
|
||||
let BASE_URL = 'https://habitica.com';
|
||||
const BASE_URL = 'https://habitica.com';
|
||||
|
||||
export default {
|
||||
mixins: [styleHelper],
|
||||
components: {
|
||||
Avatar,
|
||||
},
|
||||
mixins: [styleHelper],
|
||||
data () {
|
||||
let tweet = this.$t('levelUpShare');
|
||||
const tweet = this.$t('levelUpShare');
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
twitter,
|
||||
|
||||
@@ -37,9 +37,9 @@
|
||||
...mapState({ user: 'user.data' }),
|
||||
},
|
||||
async mounted () {
|
||||
this.$root.$on('bv::show::modal', async (modalId) => {
|
||||
this.$root.$on('bv::show::modal', async modalId => {
|
||||
if (modalId !== 'new-stuff') return;
|
||||
let response = await axios.get('/api/v4/news');
|
||||
const response = await axios.get('/api/v4/news');
|
||||
this.html = response.data.html;
|
||||
});
|
||||
},
|
||||
|
||||
@@ -45,7 +45,7 @@ export default {
|
||||
this.$root.$emit('bv::hide::modal', 'streak');
|
||||
},
|
||||
suppressModals () {
|
||||
let surpress = this.user.preferences.suppressModals.streak ? true : false;
|
||||
const surpress = !!this.user.preferences.suppressModals.streak;
|
||||
this.$store.dispatch('user:set', { 'preferences.suppressModals.streak': surpress });
|
||||
},
|
||||
},
|
||||
|
||||
@@ -52,7 +52,7 @@ export default {
|
||||
...mapState({ user: 'user.data' }),
|
||||
},
|
||||
data () {
|
||||
let tweet = this.$t('wonChallengeShare');
|
||||
const tweet = this.$t('wonChallengeShare');
|
||||
return {
|
||||
tweet,
|
||||
};
|
||||
|
||||
@@ -318,7 +318,7 @@ export default {
|
||||
async addMissedDay (numberOfDays) {
|
||||
if (!confirm(`Are you sure you want to reset the day by ${numberOfDays} day(s)?`)) return;
|
||||
|
||||
let date = moment(this.user.lastCron).subtract(numberOfDays, 'days').toDate();
|
||||
const date = moment(this.user.lastCron).subtract(numberOfDays, 'days').toDate();
|
||||
|
||||
await axios.post('/api/v4/debug/set-cron', {
|
||||
lastCron: date,
|
||||
@@ -356,11 +356,11 @@ export default {
|
||||
addExp () {
|
||||
// @TODO: Name these variables better
|
||||
let exp = 0;
|
||||
let five = 10 * this.user.stats.lvl;
|
||||
let four = Math.pow(this.user.stats.lvl, 2) * 0.25;
|
||||
let three = four + five + 139.75;
|
||||
let two = three / 10;
|
||||
let one = Math.round(two) * 10;
|
||||
const five = 10 * this.user.stats.lvl;
|
||||
const four = Math.pow(this.user.stats.lvl, 2) * 0.25;
|
||||
const three = four + five + 139.75;
|
||||
const two = three / 10;
|
||||
const one = Math.round(two) * 10;
|
||||
exp = this.user.stats.exp + one;
|
||||
|
||||
this.$store.dispatch('user:set', {
|
||||
|
||||
@@ -80,9 +80,9 @@
|
||||
|
||||
<script>
|
||||
import hello from 'hellojs';
|
||||
import { setUpAxios } from '@/libs/auth';
|
||||
import debounce from 'lodash/debounce';
|
||||
import isEmail from 'validator/lib/isEmail';
|
||||
import { setUpAxios } from '@/libs/auth';
|
||||
|
||||
import facebookSquareIcon from '@/assets/svg/facebook-square.svg';
|
||||
import googleIcon from '@/assets/svg/google.svg';
|
||||
@@ -90,7 +90,7 @@ import googleIcon from '@/assets/svg/google.svg';
|
||||
export default {
|
||||
name: 'AuthForm',
|
||||
data () {
|
||||
let data = {
|
||||
const data = {
|
||||
registering: true,
|
||||
username: '',
|
||||
email: '',
|
||||
@@ -106,13 +106,6 @@ export default {
|
||||
|
||||
return data;
|
||||
},
|
||||
mounted () {
|
||||
hello.init({
|
||||
facebook: process.env.FACEBOOK_KEY, // eslint-disable-line
|
||||
// windows: WINDOWS_CLIENT_ID,
|
||||
google: process.env.GOOGLE_CLIENT_ID, // eslint-disable-line
|
||||
});
|
||||
},
|
||||
computed: {
|
||||
emailValid () {
|
||||
if (this.email.length <= 3) return false;
|
||||
@@ -141,6 +134,13 @@ export default {
|
||||
this.validateUsername(this.username);
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
hello.init({
|
||||
facebook: process.env.FACEBOOK_KEY, // eslint-disable-line
|
||||
// windows: WINDOWS_CLIENT_ID,
|
||||
google: process.env.GOOGLE_CLIENT_ID, // eslint-disable-line
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
// eslint-disable-next-line func-names
|
||||
validateUsername: debounce(function (username) {
|
||||
@@ -165,7 +165,7 @@ export default {
|
||||
|
||||
try {
|
||||
const redirectUrl = `${window.location.protocol}//${window.location.host}`;
|
||||
let auth = await hello(network).login({
|
||||
const auth = await hello(network).login({
|
||||
scope: 'email',
|
||||
redirect_uri: redirectUrl, // eslint-disable-line camelcase
|
||||
});
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<script>
|
||||
export default {
|
||||
components: {},
|
||||
created () {
|
||||
this.logout();
|
||||
},
|
||||
methods: {
|
||||
async logout () {
|
||||
return await this.$store.dispatch('auth:logout');
|
||||
},
|
||||
},
|
||||
created () {
|
||||
this.logout();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -304,7 +304,7 @@ import googleIcon from '@/assets/svg/google.svg';
|
||||
|
||||
export default {
|
||||
data () {
|
||||
let data = {
|
||||
const data = {
|
||||
username: '',
|
||||
email: '',
|
||||
password: '',
|
||||
@@ -364,20 +364,13 @@ export default {
|
||||
return !this.passwordConfirmValid;
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
hello.init({
|
||||
facebook: process.env.FACEBOOK_KEY, // eslint-disable-line
|
||||
// windows: WINDOWS_CLIENT_ID,
|
||||
google: process.env.GOOGLE_CLIENT_ID, // eslint-disable-line
|
||||
});
|
||||
},
|
||||
watch: {
|
||||
$route: {
|
||||
handler () {
|
||||
if (this.resetPasswordSetNewOne) {
|
||||
const query = this.$route.query;
|
||||
const code = query.code;
|
||||
const hasError = query.hasError === 'true' ? true : false;
|
||||
const { query } = this.$route;
|
||||
const { code } = query;
|
||||
const hasError = query.hasError === 'true';
|
||||
if (hasError) {
|
||||
alert(query.message);
|
||||
this.$router.push({ name: 'login' });
|
||||
@@ -400,6 +393,13 @@ export default {
|
||||
this.validateUsername(this.username);
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
hello.init({
|
||||
facebook: process.env.FACEBOOK_KEY, // eslint-disable-line
|
||||
// windows: WINDOWS_CLIENT_ID,
|
||||
google: process.env.GOOGLE_CLIENT_ID, // eslint-disable-line
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
// eslint-disable-next-line func-names
|
||||
validateUsername: debounce(function (username) {
|
||||
@@ -488,7 +488,7 @@ export default {
|
||||
} catch (e) {} // eslint-disable-line
|
||||
|
||||
const redirectUrl = `${window.location.protocol}//${window.location.host}`;
|
||||
let auth = await hello(network).login({
|
||||
const auth = await hello(network).login({
|
||||
scope: 'email',
|
||||
// explicitly pass the redirect url or it might redirect to /home
|
||||
redirect_uri: redirectUrl, // eslint-disable-line camelcase
|
||||
|
||||
@@ -146,9 +146,9 @@ export default {
|
||||
return val;
|
||||
},
|
||||
backgroundClass () {
|
||||
let background = this.member.preferences.background;
|
||||
const { background } = this.member.preferences;
|
||||
|
||||
let allowToShowBackground = !this.avatarOnly || this.withBackground;
|
||||
const allowToShowBackground = !this.avatarOnly || this.withBackground;
|
||||
|
||||
if (this.overrideAvatarGear && this.overrideAvatarGear.background) {
|
||||
return `background_${this.overrideAvatarGear.background}`;
|
||||
@@ -169,7 +169,7 @@ export default {
|
||||
};
|
||||
},
|
||||
skinClass () {
|
||||
let baseClass = `skin_${this.member.preferences.skin}`;
|
||||
const baseClass = `skin_${this.member.preferences.skin}`;
|
||||
|
||||
return `${baseClass}${this.member.preferences.sleep ? '_sleep' : ''}`;
|
||||
},
|
||||
@@ -196,19 +196,19 @@ export default {
|
||||
},
|
||||
hideGear (gearType) {
|
||||
if (gearType === 'weapon') {
|
||||
let equippedWeapon = this.member.items.gear[this.costumeClass][gearType];
|
||||
const equippedWeapon = this.member.items.gear[this.costumeClass][gearType];
|
||||
|
||||
if (!equippedWeapon) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let equippedIsTwoHanded = this.flatGear[equippedWeapon].twoHanded;
|
||||
let hasOverrideShield = this.overrideAvatarGear && this.overrideAvatarGear.shield;
|
||||
const equippedIsTwoHanded = this.flatGear[equippedWeapon].twoHanded;
|
||||
const hasOverrideShield = this.overrideAvatarGear && this.overrideAvatarGear.shield;
|
||||
|
||||
return equippedIsTwoHanded && hasOverrideShield;
|
||||
} else if (gearType === 'shield') {
|
||||
let overrideWeapon = this.overrideAvatarGear && this.overrideAvatarGear.weapon;
|
||||
let overrideIsTwoHanded = overrideWeapon && this.flatGear[overrideWeapon].twoHanded;
|
||||
} if (gearType === 'shield') {
|
||||
const overrideWeapon = this.overrideAvatarGear && this.overrideAvatarGear.weapon;
|
||||
const overrideIsTwoHanded = overrideWeapon && this.flatGear[overrideWeapon].twoHanded;
|
||||
|
||||
return overrideIsTwoHanded;
|
||||
}
|
||||
@@ -218,10 +218,9 @@ export default {
|
||||
this.$root.$emit('castEnd', this.member, 'user', e);
|
||||
},
|
||||
showAvatar () {
|
||||
if (!this.showVisualBuffs)
|
||||
return true;
|
||||
if (!this.showVisualBuffs) return true;
|
||||
|
||||
let buffs = this.member.stats.buffs;
|
||||
const { buffs } = this.member.stats;
|
||||
|
||||
return !buffs.snowball && !buffs.spookySparkles && !buffs.shinySeed && !buffs.seafoam;
|
||||
},
|
||||
|
||||
@@ -34,9 +34,6 @@
|
||||
|
||||
|
||||
export default {
|
||||
props: [
|
||||
'editing',
|
||||
],
|
||||
components: {
|
||||
subMenu,
|
||||
customizeOptions,
|
||||
@@ -46,6 +43,9 @@
|
||||
userStateMixin,
|
||||
avatarEditorUtilies,
|
||||
],
|
||||
props: [
|
||||
'editing',
|
||||
],
|
||||
data () {
|
||||
return {
|
||||
specialShirtKeys,
|
||||
@@ -73,8 +73,8 @@
|
||||
},
|
||||
specialShirts () {
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.specialShirtKeys;
|
||||
let options = keys.map(key => this.mapKeysToOption(key, 'shirt'));
|
||||
const keys = this.specialShirtKeys;
|
||||
const options = keys.map(key => this.mapKeysToOption(key, 'shirt'));
|
||||
return options;
|
||||
},
|
||||
},
|
||||
|
||||
@@ -28,10 +28,10 @@
|
||||
import { avatarEditorUtilies } from '../../mixins/avatarEditUtilities';
|
||||
|
||||
export default {
|
||||
props: ['items', 'currentValue', 'fullSet'],
|
||||
mixins: [
|
||||
avatarEditorUtilies,
|
||||
],
|
||||
props: ['items', 'currentValue', 'fullSet'],
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
|
||||
@@ -49,9 +49,6 @@
|
||||
|
||||
|
||||
export default {
|
||||
props: [
|
||||
'editing',
|
||||
],
|
||||
components: {
|
||||
subMenu,
|
||||
customizeOptions,
|
||||
@@ -61,6 +58,9 @@
|
||||
userStateMixin,
|
||||
avatarEditorUtilies,
|
||||
],
|
||||
props: [
|
||||
'editing',
|
||||
],
|
||||
data () {
|
||||
return {
|
||||
animalItemKeys: {
|
||||
@@ -126,18 +126,18 @@
|
||||
return items;
|
||||
},
|
||||
eyewear () {
|
||||
let keys = [
|
||||
const keys = [
|
||||
'blackTopFrame', 'blueTopFrame', 'greenTopFrame', 'pinkTopFrame', 'redTopFrame', 'whiteTopFrame', 'yellowTopFrame',
|
||||
'blackHalfMoon', 'blueHalfMoon', 'greenHalfMoon', 'pinkHalfMoon', 'redHalfMoon', 'whiteHalfMoon', 'yellowHalfMoon',
|
||||
];
|
||||
let options = keys.map(key => {
|
||||
let newKey = `eyewear_special_${key}`;
|
||||
let option = {};
|
||||
const options = keys.map(key => {
|
||||
const newKey = `eyewear_special_${key}`;
|
||||
const option = {};
|
||||
option.key = key;
|
||||
option.active = this.user.preferences.costume ? this.user.items.gear.costume.eyewear === newKey : this.user.items.gear.equipped.eyewear === newKey;
|
||||
option.class = `eyewear_special_${key}`;
|
||||
option.click = () => {
|
||||
let type = this.user.preferences.costume ? 'costume' : 'equipped';
|
||||
const type = this.user.preferences.costume ? 'costume' : 'equipped';
|
||||
|
||||
return this.equip(newKey, type);
|
||||
};
|
||||
@@ -150,20 +150,20 @@
|
||||
},
|
||||
specialShirts () {
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.specialShirtKeys;
|
||||
let options = keys.map(key => this.mapKeysToOption(key, 'shirt'));
|
||||
const keys = this.specialShirtKeys;
|
||||
const options = keys.map(key => this.mapKeysToOption(key, 'shirt'));
|
||||
return options;
|
||||
},
|
||||
headbands () {
|
||||
let keys = ['blackHeadband', 'blueHeadband', 'greenHeadband', 'pinkHeadband', 'redHeadband', 'whiteHeadband', 'yellowHeadband'];
|
||||
let options = keys.map(key => {
|
||||
let newKey = `headAccessory_special_${key}`;
|
||||
let option = {};
|
||||
const keys = ['blackHeadband', 'blueHeadband', 'greenHeadband', 'pinkHeadband', 'redHeadband', 'whiteHeadband', 'yellowHeadband'];
|
||||
const options = keys.map(key => {
|
||||
const newKey = `headAccessory_special_${key}`;
|
||||
const option = {};
|
||||
option.key = key;
|
||||
option.active = this.user.preferences.costume ? this.user.items.gear.costume.headAccessory === newKey : this.user.items.gear.equipped.headAccessory === newKey;
|
||||
option.class = `headAccessory_special_${option.key} headband`;
|
||||
option.click = () => {
|
||||
let type = this.user.preferences.costume ? 'costume' : 'equipped';
|
||||
const type = this.user.preferences.costume ? 'costume' : 'equipped';
|
||||
return this.equip(newKey, type);
|
||||
};
|
||||
return option;
|
||||
@@ -171,34 +171,30 @@
|
||||
return options;
|
||||
},
|
||||
chairs () {
|
||||
let options = this.chairKeys.map(key => {
|
||||
let option = {};
|
||||
const options = this.chairKeys.map(key => {
|
||||
const option = {};
|
||||
option.key = key;
|
||||
if (key === 'none') {
|
||||
option.none = true;
|
||||
}
|
||||
option.active = this.user.preferences.chair === key;
|
||||
option.class = `button_chair_${key} chair ${key.includes('handleless_') ? 'handleless' : ''}`;
|
||||
option.click = () => {
|
||||
return this.set({'preferences.chair': key});
|
||||
};
|
||||
option.click = () => this.set({ 'preferences.chair': key });
|
||||
return option;
|
||||
});
|
||||
return options;
|
||||
},
|
||||
flowers () {
|
||||
let keys = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
|
||||
let options = keys.map(key => {
|
||||
let option = {};
|
||||
const keys = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
|
||||
const options = keys.map(key => {
|
||||
const option = {};
|
||||
option.key = key;
|
||||
if (key === 0) {
|
||||
option.none = true;
|
||||
}
|
||||
option.active = this.user.preferences.hair.flower === key;
|
||||
option.class = `hair_flower_${key} flower`;
|
||||
option.click = () => {
|
||||
return this.set({'preferences.hair.flower': key});
|
||||
};
|
||||
option.click = () => this.set({ 'preferences.hair.flower': key });
|
||||
return option;
|
||||
});
|
||||
return options;
|
||||
@@ -211,12 +207,12 @@
|
||||
animalItems (category) {
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.animalItemKeys[category];
|
||||
let options = keys.map(key => {
|
||||
let newKey = `${category}_special_${key}`;
|
||||
let userPurchased = this.user.items.gear.owned[newKey];
|
||||
const keys = this.animalItemKeys[category];
|
||||
const options = keys.map(key => {
|
||||
const newKey = `${category}_special_${key}`;
|
||||
const userPurchased = this.user.items.gear.owned[newKey];
|
||||
|
||||
let option = {};
|
||||
const option = {};
|
||||
option.key = key;
|
||||
option.active = this.user.preferences.costume ? this.user.items.gear.costume[category] === newKey : this.user.items.gear.equipped[category] === newKey;
|
||||
option.class = `headAccessory_special_${option.key} ${category}`;
|
||||
@@ -235,21 +231,18 @@
|
||||
option.click = () => {
|
||||
if (option.gemLocked) {
|
||||
return this.unlock(`items.gear.owned.${newKey}`);
|
||||
} else if (option.goldLocked) {
|
||||
} if (option.goldLocked) {
|
||||
return this.buy(newKey);
|
||||
} else {
|
||||
let type = this.user.preferences.costume ? 'costume' : 'equipped';
|
||||
return this.equip(newKey, type);
|
||||
}
|
||||
const type = this.user.preferences.costume ? 'costume' : 'equipped';
|
||||
return this.equip(newKey, type);
|
||||
};
|
||||
return option;
|
||||
});
|
||||
return options;
|
||||
},
|
||||
animalItemsUnlockString (category) {
|
||||
const keys = this.animalItemKeys[category].map(key => {
|
||||
return `items.gear.owned.${category}_special_${key}`;
|
||||
});
|
||||
const keys = this.animalItemKeys[category].map(key => `items.gear.owned.${category}_special_${key}`);
|
||||
|
||||
return keys.join(',');
|
||||
},
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import groupBy from 'lodash/groupBy';
|
||||
import appearance from '@/../../common/script/content/appearance';
|
||||
import { subPageMixin } from '../../mixins/subPage';
|
||||
import { userStateMixin } from '../../mixins/userState';
|
||||
@@ -50,15 +51,11 @@
|
||||
import customizeOptions from './customize-options';
|
||||
import gem from '@/assets/svg/gem.svg';
|
||||
import appearanceSets from '@/../../common/script/content/appearance/sets';
|
||||
import groupBy from 'lodash/groupBy';
|
||||
|
||||
const hairColorBySet = groupBy(appearance.hair.color, 'set.key');
|
||||
const freeHairColorKeys = hairColorBySet[undefined].map(s => s.key);
|
||||
|
||||
export default {
|
||||
props: [
|
||||
'editing',
|
||||
],
|
||||
components: {
|
||||
subMenu,
|
||||
customizeOptions,
|
||||
@@ -68,6 +65,9 @@
|
||||
userStateMixin,
|
||||
avatarEditorUtilies,
|
||||
],
|
||||
props: [
|
||||
'editing',
|
||||
],
|
||||
data () {
|
||||
return {
|
||||
freeHairColorKeys,
|
||||
@@ -115,15 +115,13 @@
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
|
||||
let seasonalHairColors = [];
|
||||
for (let key in hairColorBySet) {
|
||||
let set = hairColorBySet[key];
|
||||
const seasonalHairColors = [];
|
||||
for (const key in hairColorBySet) {
|
||||
const set = hairColorBySet[key];
|
||||
|
||||
let keys = set.map(item => {
|
||||
return item.key;
|
||||
});
|
||||
const keys = set.map(item => item.key);
|
||||
|
||||
let options = keys.map(optionKey => {
|
||||
const options = keys.map(optionKey => {
|
||||
const option = this.mapKeysToOption(optionKey, 'hair', 'color', key);
|
||||
return option;
|
||||
});
|
||||
@@ -133,7 +131,7 @@
|
||||
text = appearanceSets[key].text();
|
||||
}
|
||||
|
||||
let compiledSet = {
|
||||
const compiledSet = {
|
||||
key,
|
||||
options,
|
||||
keys,
|
||||
@@ -147,26 +145,22 @@
|
||||
premiumHairColors () {
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.premiumHairColorKeys;
|
||||
let options = keys.map(key => {
|
||||
return this.mapKeysToOption(key, 'hair', 'color');
|
||||
});
|
||||
const keys = this.premiumHairColorKeys;
|
||||
const options = keys.map(key => this.mapKeysToOption(key, 'hair', 'color'));
|
||||
return options;
|
||||
},
|
||||
baseHair2 () {
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.baseHair2Keys;
|
||||
let options = keys.map(key => {
|
||||
return this.mapKeysToOption(key, 'hair', 'base');
|
||||
});
|
||||
const keys = this.baseHair2Keys;
|
||||
const options = keys.map(key => this.mapKeysToOption(key, 'hair', 'base'));
|
||||
return options;
|
||||
},
|
||||
baseHair3 () {
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.baseHair3Keys;
|
||||
let options = keys.map(key => {
|
||||
const keys = this.baseHair3Keys;
|
||||
const options = keys.map(key => {
|
||||
const option = this.mapKeysToOption(key, 'hair', 'base');
|
||||
return option;
|
||||
});
|
||||
@@ -175,28 +169,22 @@
|
||||
baseHair4 () {
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.baseHair4Keys;
|
||||
let options = keys.map(key => {
|
||||
return this.mapKeysToOption(key, 'hair', 'base');
|
||||
});
|
||||
const keys = this.baseHair4Keys;
|
||||
const options = keys.map(key => this.mapKeysToOption(key, 'hair', 'base'));
|
||||
return options;
|
||||
},
|
||||
baseHair5 () {
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.baseHair5Keys;
|
||||
let options = keys.map(key => {
|
||||
return this.mapKeysToOption(key, 'hair', 'mustache');
|
||||
});
|
||||
const keys = this.baseHair5Keys;
|
||||
const options = keys.map(key => this.mapKeysToOption(key, 'hair', 'mustache'));
|
||||
return options;
|
||||
},
|
||||
baseHair6 () {
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
let keys = this.baseHair6Keys;
|
||||
let options = keys.map(key => {
|
||||
return this.mapKeysToOption(key, 'hair', 'beard');
|
||||
});
|
||||
const keys = this.baseHair6Keys;
|
||||
const options = keys.map(key => this.mapKeysToOption(key, 'hair', 'beard'));
|
||||
return options;
|
||||
},
|
||||
hairBangs () {
|
||||
@@ -282,7 +270,7 @@
|
||||
// If item types are specified, count them
|
||||
if (types && types.length > 0) {
|
||||
// Types can be undefined, so we must check them.
|
||||
types.forEach((type) => {
|
||||
types.forEach(type => {
|
||||
if (this.user.purchased[category][type]) {
|
||||
purchasedItemsLengths
|
||||
.push(Object.keys(this.user.purchased[category][type]).length);
|
||||
@@ -293,10 +281,10 @@
|
||||
|
||||
// If types are not specified, recursively
|
||||
// search for purchased items in the category
|
||||
const findPurchasedItems = (item) => {
|
||||
const findPurchasedItems = item => {
|
||||
if (typeof item === 'object') {
|
||||
Object.values(item)
|
||||
.forEach((innerItem) => {
|
||||
.forEach(innerItem => {
|
||||
if (typeof innerItem === 'boolean' && innerItem === true) {
|
||||
purchasedItemsCounter += 1;
|
||||
}
|
||||
@@ -320,7 +308,7 @@
|
||||
|
||||
const allItemsLengths = [];
|
||||
// Key sets must be specify correctly.
|
||||
keySets.forEach((keySet) => {
|
||||
keySets.forEach(keySet => {
|
||||
allItemsLengths.push(Object.keys(this[keySet]).length);
|
||||
});
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import groupBy from 'lodash/groupBy';
|
||||
import appearance from '@/../../common/script/content/appearance';
|
||||
import { subPageMixin } from '../../mixins/subPage';
|
||||
import { userStateMixin } from '../../mixins/userState';
|
||||
@@ -25,7 +26,6 @@
|
||||
import customizeOptions from './customize-options';
|
||||
import gem from '@/assets/svg/gem.svg';
|
||||
|
||||
import groupBy from 'lodash/groupBy';
|
||||
|
||||
const skinsBySet = groupBy(appearance.skin, 'set.key');
|
||||
|
||||
@@ -35,9 +35,6 @@
|
||||
|
||||
|
||||
export default {
|
||||
props: [
|
||||
'editing',
|
||||
],
|
||||
components: {
|
||||
subMenu,
|
||||
customizeOptions,
|
||||
@@ -47,6 +44,9 @@
|
||||
userStateMixin,
|
||||
avatarEditorUtilies,
|
||||
],
|
||||
props: [
|
||||
'editing',
|
||||
],
|
||||
data () {
|
||||
return {
|
||||
freeSkinKeys,
|
||||
@@ -69,15 +69,13 @@
|
||||
// @TODO: For some resonse when I use $set on the user purchases object, this is not recomputed. Hack for now
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
|
||||
let seasonalSkins = [];
|
||||
for (let setKey in skinsBySet) {
|
||||
let set = skinsBySet[setKey];
|
||||
const seasonalSkins = [];
|
||||
for (const setKey in skinsBySet) {
|
||||
const set = skinsBySet[setKey];
|
||||
|
||||
let keys = set.map(item => {
|
||||
return item.key;
|
||||
});
|
||||
const keys = set.map(item => item.key);
|
||||
|
||||
let options = keys.map(optionKey => {
|
||||
const options = keys.map(optionKey => {
|
||||
const option = this.mapKeysToOption(optionKey, 'skin', '', setKey);
|
||||
|
||||
return option;
|
||||
@@ -88,7 +86,7 @@
|
||||
text = appearanceSets[setKey].text();
|
||||
}
|
||||
|
||||
let compiledSet = {
|
||||
const compiledSet = {
|
||||
key: setKey,
|
||||
options,
|
||||
keys,
|
||||
|
||||
@@ -167,8 +167,6 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
const TASK_KEYS_TO_REMOVE = ['_id', 'completed', 'date', 'dateCompleted', 'history', 'id', 'streak', 'createdAt', 'challenge'];
|
||||
|
||||
import Vue from 'vue';
|
||||
import findIndex from 'lodash/findIndex';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
@@ -194,9 +192,9 @@ import gemIcon from '@/assets/svg/gem.svg';
|
||||
import memberIcon from '@/assets/svg/member-icon.svg';
|
||||
import calendarIcon from '@/assets/svg/calendar.svg';
|
||||
|
||||
const TASK_KEYS_TO_REMOVE = ['_id', 'completed', 'date', 'dateCompleted', 'history', 'id', 'streak', 'createdAt', 'challenge'];
|
||||
|
||||
export default {
|
||||
props: ['challengeId'],
|
||||
mixins: [challengeMemberSearchMixin],
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
},
|
||||
@@ -212,6 +210,8 @@ export default {
|
||||
userLink,
|
||||
groupLink,
|
||||
},
|
||||
mixins: [challengeMemberSearchMixin],
|
||||
props: ['challengeId'],
|
||||
data () {
|
||||
return {
|
||||
searchId: '',
|
||||
@@ -267,11 +267,11 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
cleanUpTask (task) {
|
||||
let cleansedTask = omit(task, TASK_KEYS_TO_REMOVE);
|
||||
const cleansedTask = omit(task, TASK_KEYS_TO_REMOVE);
|
||||
|
||||
// Copy checklists but reset to uncomplete and assign new id
|
||||
if (!cleansedTask.checklist) cleansedTask.checklist = [];
|
||||
cleansedTask.checklist.forEach((item) => {
|
||||
cleansedTask.checklist.forEach(item => {
|
||||
item.completed = false;
|
||||
item.id = uuid();
|
||||
});
|
||||
@@ -285,14 +285,14 @@ export default {
|
||||
async loadChallenge () {
|
||||
this.challenge = await this.$store.dispatch('challenges:getChallenge', { challengeId: this.searchId });
|
||||
this.members = await this.loadMembers({ challengeId: this.searchId, includeAllPublicFields: true });
|
||||
let tasks = await this.$store.dispatch('tasks:getChallengeTasks', {challengeId: this.searchId});
|
||||
const tasks = await this.$store.dispatch('tasks:getChallengeTasks', { challengeId: this.searchId });
|
||||
this.tasksByType = {
|
||||
habit: [],
|
||||
daily: [],
|
||||
todo: [],
|
||||
reward: [],
|
||||
};
|
||||
tasks.forEach((task) => {
|
||||
tasks.forEach(task => {
|
||||
this.tasksByType[task.type].push(task);
|
||||
});
|
||||
},
|
||||
@@ -337,15 +337,11 @@ export default {
|
||||
this.tasksByType[task.type].push(task);
|
||||
},
|
||||
taskEdited (task) {
|
||||
let index = findIndex(this.tasksByType[task.type], (taskItem) => {
|
||||
return taskItem._id === task._id;
|
||||
});
|
||||
const index = findIndex(this.tasksByType[task.type], taskItem => taskItem._id === task._id);
|
||||
this.tasksByType[task.type].splice(index, 1, task);
|
||||
},
|
||||
taskDestroyed (task) {
|
||||
let index = findIndex(this.tasksByType[task.type], (taskItem) => {
|
||||
return taskItem._id === task._id;
|
||||
});
|
||||
const index = findIndex(this.tasksByType[task.type], taskItem => taskItem._id === task._id);
|
||||
this.tasksByType[task.type].splice(index, 1);
|
||||
},
|
||||
showMemberModal () {
|
||||
|
||||
@@ -320,14 +320,6 @@
|
||||
import officialIcon from '@/assets/svg/official.svg';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
challenge: {
|
||||
required: true,
|
||||
},
|
||||
fullLayout: {
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
userLink,
|
||||
groupLink,
|
||||
@@ -336,6 +328,14 @@
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
},
|
||||
props: {
|
||||
challenge: {
|
||||
required: true,
|
||||
},
|
||||
fullLayout: {
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
|
||||
@@ -23,10 +23,10 @@ import axios from 'axios';
|
||||
import Column from '../tasks/column';
|
||||
|
||||
export default {
|
||||
props: ['challengeId'],
|
||||
components: {
|
||||
TaskColumn: Column,
|
||||
},
|
||||
props: ['challengeId'],
|
||||
data () {
|
||||
return {
|
||||
columns: ['habit', 'daily', 'todo', 'reward'],
|
||||
@@ -41,18 +41,6 @@ export default {
|
||||
isAdmin: false,
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
this.$root.$on('habitica:challenge:member-progress', (data) => {
|
||||
if (!data.progressMemberId) return;
|
||||
this.memberId = data.progressMemberId;
|
||||
this.isLeader = data.isLeader;
|
||||
this.isAdmin = data.isAdmin;
|
||||
this.$root.$emit('bv::show::modal', 'challenge-member-modal');
|
||||
});
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.$root.$off('habitica:challenge:member-progress');
|
||||
},
|
||||
watch: {
|
||||
async memberId (id) {
|
||||
if (!id) return;
|
||||
@@ -63,13 +51,25 @@ export default {
|
||||
reward: [],
|
||||
};
|
||||
|
||||
let response = await axios.get(`/api/v4/challenges/${this.challengeId}/members/${this.memberId}`);
|
||||
let tasks = response.data.data.tasks;
|
||||
tasks.forEach((task) => {
|
||||
const response = await axios.get(`/api/v4/challenges/${this.challengeId}/members/${this.memberId}`);
|
||||
const { tasks } = response.data.data;
|
||||
tasks.forEach(task => {
|
||||
this.tasksByType[task.type].push(task);
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.$root.$on('habitica:challenge:member-progress', data => {
|
||||
if (!data.progressMemberId) return;
|
||||
this.memberId = data.progressMemberId;
|
||||
this.isLeader = data.isLeader;
|
||||
this.isAdmin = data.isAdmin;
|
||||
this.$root.$emit('bv::show::modal', 'challenge-member-modal');
|
||||
});
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.$root.$off('habitica:challenge:member-progress');
|
||||
},
|
||||
methods: {
|
||||
async closeChallenge () {
|
||||
this.challenge = await this.$store.dispatch('challenges:selectChallengeWinner', {
|
||||
|
||||
@@ -138,12 +138,12 @@ import { TAVERN_ID, MIN_SHORTNAME_SIZE_FOR_CHALLENGES, MAX_SUMMARY_SIZE_FOR_CHAL
|
||||
import { mapState } from '@/libs/store';
|
||||
|
||||
export default {
|
||||
props: ['groupId'],
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
},
|
||||
props: ['groupId'],
|
||||
data () {
|
||||
let categoryOptions = [
|
||||
const categoryOptions = [
|
||||
{
|
||||
label: 'habitica_official',
|
||||
key: 'habitica_official',
|
||||
@@ -201,11 +201,11 @@ export default {
|
||||
key: 'time_management',
|
||||
},
|
||||
];
|
||||
let hashedCategories = {};
|
||||
categoryOptions.forEach((category) => {
|
||||
const hashedCategories = {};
|
||||
categoryOptions.forEach(category => {
|
||||
hashedCategories[category.key] = category.label;
|
||||
});
|
||||
let categoriesHashByKey = hashedCategories;
|
||||
const categoriesHashByKey = hashedCategories;
|
||||
|
||||
return {
|
||||
workingChallenge: {
|
||||
@@ -233,24 +233,6 @@ export default {
|
||||
groups: [],
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
this.$root.$on('habitica:clone-challenge', (data) => {
|
||||
if (!data.challenge) return;
|
||||
this.cloning = true;
|
||||
this.cloningChallengeId = data.challenge._id;
|
||||
this.$store.state.challengeOptions.workingChallenge = Object.assign({}, this.$store.state.challengeOptions.workingChallenge, data.challenge);
|
||||
this.$root.$emit('bv::show::modal', 'challenge-modal');
|
||||
});
|
||||
this.$root.$on('habitica:update-challenge', (data) => {
|
||||
if (!data.challenge) return;
|
||||
this.cloning = false;
|
||||
this.$store.state.challengeOptions.workingChallenge = Object.assign({}, this.$store.state.challengeOptions.workingChallenge, data.challenge);
|
||||
this.$root.$emit('bv::show::modal', 'challenge-modal');
|
||||
});
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.$root.$off('habitica:clone-challenge');
|
||||
},
|
||||
watch: {
|
||||
user () {
|
||||
if (!this.challenge) this.workingChallenge.leader = this.user._id;
|
||||
@@ -262,6 +244,24 @@ export default {
|
||||
this.setUpWorkingChallenge();
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.$root.$on('habitica:clone-challenge', data => {
|
||||
if (!data.challenge) return;
|
||||
this.cloning = true;
|
||||
this.cloningChallengeId = data.challenge._id;
|
||||
this.$store.state.challengeOptions.workingChallenge = { ...this.$store.state.challengeOptions.workingChallenge, ...data.challenge };
|
||||
this.$root.$emit('bv::show::modal', 'challenge-modal');
|
||||
});
|
||||
this.$root.$on('habitica:update-challenge', data => {
|
||||
if (!data.challenge) return;
|
||||
this.cloning = false;
|
||||
this.$store.state.challengeOptions.workingChallenge = { ...this.$store.state.challengeOptions.workingChallenge, ...data.challenge };
|
||||
this.$root.$emit('bv::show::modal', 'challenge-modal');
|
||||
});
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.$root.$off('habitica:clone-challenge');
|
||||
},
|
||||
computed: {
|
||||
...mapState({ user: 'user.data' }),
|
||||
creating () {
|
||||
@@ -274,19 +274,18 @@ export default {
|
||||
return this.$t('editingChallenge');
|
||||
},
|
||||
charactersRemaining () {
|
||||
let currentLength = this.workingChallenge.summary ? this.workingChallenge.summary.length : 0;
|
||||
const currentLength = this.workingChallenge.summary ? this.workingChallenge.summary.length : 0;
|
||||
return MAX_SUMMARY_SIZE_FOR_CHALLENGES - currentLength;
|
||||
},
|
||||
maxPrize () {
|
||||
let userBalance = this.user.balance || 0;
|
||||
userBalance = userBalance * 4;
|
||||
userBalance *= 4;
|
||||
|
||||
let groupBalance = 0;
|
||||
let group;
|
||||
this.groups.forEach(item => {
|
||||
if (item._id === this.workingChallenge.group) {
|
||||
group = item;
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -301,14 +300,13 @@ export default {
|
||||
return 0;
|
||||
},
|
||||
insufficientGemsForTavernChallenge () {
|
||||
let balance = this.user.balance || 0;
|
||||
let isForTavern = this.workingChallenge.group === TAVERN_ID;
|
||||
const balance = this.user.balance || 0;
|
||||
const isForTavern = this.workingChallenge.group === TAVERN_ID;
|
||||
|
||||
if (isForTavern) {
|
||||
return balance <= 0;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
challenge () {
|
||||
return this.$store.state.challengeOptions.workingChallenge;
|
||||
@@ -342,7 +340,7 @@ export default {
|
||||
|
||||
if (!this.challenge) return;
|
||||
|
||||
this.workingChallenge = Object.assign({}, this.workingChallenge, this.challenge);
|
||||
this.workingChallenge = { ...this.workingChallenge, ...this.challenge };
|
||||
// @TODO: Should we use a separate field? I think the API expects `group` but it is confusing
|
||||
this.workingChallenge.group = this.workingChallenge.group._id;
|
||||
this.workingChallenge.categories = [];
|
||||
@@ -381,7 +379,7 @@ export default {
|
||||
async createChallenge () {
|
||||
this.loading = true;
|
||||
// @TODO: improve error handling, add it to updateChallenge, make errors translatable. Suggestion: `<% fieldName %> is required` where possible, where `fieldName` is inserted as the translatable string that's used for the field header.
|
||||
let errors = [];
|
||||
const errors = [];
|
||||
|
||||
if (!this.workingChallenge.name) errors.push(this.$t('nameRequired'));
|
||||
if (this.workingChallenge.shortName.length < MIN_SHORTNAME_SIZE_FOR_CHALLENGES) errors.push(this.$t('tagTooShort'));
|
||||
@@ -398,17 +396,17 @@ export default {
|
||||
}
|
||||
|
||||
this.workingChallenge.timestamp = new Date().getTime();
|
||||
let categoryKeys = this.workingChallenge.categories;
|
||||
let serverCategories = [];
|
||||
const categoryKeys = this.workingChallenge.categories;
|
||||
const serverCategories = [];
|
||||
categoryKeys.forEach(key => {
|
||||
let catName = this.categoriesHashByKey[key];
|
||||
const catName = this.categoriesHashByKey[key];
|
||||
serverCategories.push({
|
||||
slug: key,
|
||||
name: catName,
|
||||
});
|
||||
});
|
||||
|
||||
let challengeDetails = clone(this.workingChallenge);
|
||||
const challengeDetails = clone(this.workingChallenge);
|
||||
challengeDetails.categories = serverCategories;
|
||||
|
||||
let challenge;
|
||||
@@ -423,9 +421,7 @@ export default {
|
||||
}
|
||||
|
||||
// Update Group Prize
|
||||
let challengeGroup = this.groups.find(group => {
|
||||
return group._id === this.workingChallenge.group;
|
||||
});
|
||||
const challengeGroup = this.groups.find(group => group._id === this.workingChallenge.group);
|
||||
|
||||
// @TODO: Share with server
|
||||
const prizeCost = this.workingChallenge.prize / 4;
|
||||
@@ -435,7 +431,7 @@ export default {
|
||||
// Group pays for all of prize
|
||||
} else if (challengeGroup && userIsLeader && challengeGroup.balance > 0) {
|
||||
// User pays remainder of prize cost after group
|
||||
let remainder = prizeCost - challengeGroup.balance;
|
||||
const remainder = prizeCost - challengeGroup.balance;
|
||||
this.user.balance -= remainder;
|
||||
} else {
|
||||
// User pays for all of prize
|
||||
@@ -449,18 +445,18 @@ export default {
|
||||
this.$router.push(`/challenges/${challenge._id}`);
|
||||
},
|
||||
updateChallenge () {
|
||||
let categoryKeys = this.workingChallenge.categories;
|
||||
let serverCategories = [];
|
||||
const categoryKeys = this.workingChallenge.categories;
|
||||
const serverCategories = [];
|
||||
categoryKeys.forEach(key => {
|
||||
let newKey = key.trim();
|
||||
let catName = this.categoriesHashByKey[newKey];
|
||||
const newKey = key.trim();
|
||||
const catName = this.categoriesHashByKey[newKey];
|
||||
serverCategories.push({
|
||||
slug: newKey,
|
||||
name: catName,
|
||||
});
|
||||
});
|
||||
|
||||
let challengeDetails = clone(this.workingChallenge);
|
||||
const challengeDetails = clone(this.workingChallenge);
|
||||
challengeDetails.categories = serverCategories;
|
||||
|
||||
this.$emit('updatedChallenge', {
|
||||
|
||||
@@ -74,10 +74,10 @@ div
|
||||
import memberSearchDropdown from '@/components/members/memberSearchDropdown';
|
||||
|
||||
export default {
|
||||
props: ['challengeId', 'members', 'prize'],
|
||||
components: {
|
||||
memberSearchDropdown,
|
||||
},
|
||||
props: ['challengeId', 'members', 'prize'],
|
||||
data () {
|
||||
return {
|
||||
winner: {},
|
||||
|
||||
@@ -66,6 +66,8 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import MugenScroll from 'vue-mugen-scroll';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { mapState } from '@/libs/store';
|
||||
|
||||
import Sidebar from './sidebar';
|
||||
@@ -75,18 +77,15 @@ import challengeUtilities from '@/mixins/challengeUtilities';
|
||||
|
||||
import positiveIcon from '@/assets/svg/positive.svg';
|
||||
|
||||
import MugenScroll from 'vue-mugen-scroll';
|
||||
|
||||
import debounce from 'lodash/debounce';
|
||||
|
||||
export default {
|
||||
mixins: [challengeUtilities],
|
||||
components: {
|
||||
Sidebar,
|
||||
ChallengeItem,
|
||||
challengeModal,
|
||||
MugenScroll,
|
||||
},
|
||||
mixins: [challengeUtilities],
|
||||
data () {
|
||||
return {
|
||||
loading: true,
|
||||
|
||||
@@ -46,11 +46,11 @@ div
|
||||
import challengeIcon from '@/assets/svg/challenge.svg';
|
||||
|
||||
export default {
|
||||
props: ['groupId'],
|
||||
components: {
|
||||
challengeModal,
|
||||
challengeItem,
|
||||
},
|
||||
props: ['groupId'],
|
||||
computed: {
|
||||
...mapState({ user: 'user.data' }),
|
||||
},
|
||||
@@ -66,14 +66,14 @@ div
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
},
|
||||
mounted () {
|
||||
this.loadChallenges();
|
||||
},
|
||||
watch: {
|
||||
async groupId () {
|
||||
this.loadChallenges();
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.loadChallenges();
|
||||
},
|
||||
methods: {
|
||||
async loadChallenges () {
|
||||
this.groupIdForChallenges = this.groupId;
|
||||
|
||||
@@ -19,16 +19,14 @@ import { mapState } from '@/libs/store';
|
||||
import notifications from '@/mixins/notifications';
|
||||
|
||||
export default {
|
||||
props: ['challengeId'],
|
||||
mixins: [notifications],
|
||||
props: ['challengeId'],
|
||||
computed: {
|
||||
...mapState({ user: 'user.data' }),
|
||||
},
|
||||
methods: {
|
||||
async leaveChallenge (keep) {
|
||||
let index = findIndex(this.user.challenges, (id) => {
|
||||
return id === this.challengeId;
|
||||
});
|
||||
const index = findIndex(this.user.challenges, id => id === this.challengeId);
|
||||
this.user.challenges.splice(index, 1);
|
||||
await this.$store.dispatch('challenges:leaveChallenge', {
|
||||
challengeId: this.challengeId,
|
||||
|
||||
@@ -80,6 +80,8 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import MugenScroll from 'vue-mugen-scroll';
|
||||
import debounce from 'lodash/debounce';
|
||||
import { mapState } from '@/libs/store';
|
||||
import Sidebar from './sidebar';
|
||||
import ChallengeItem from './challengeItem';
|
||||
@@ -88,18 +90,16 @@ import challengeUtilities from '@/mixins/challengeUtilities';
|
||||
|
||||
import challengeIcon from '@/assets/svg/challenge.svg';
|
||||
import positiveIcon from '@/assets/svg/positive.svg';
|
||||
import MugenScroll from 'vue-mugen-scroll';
|
||||
|
||||
import debounce from 'lodash/debounce';
|
||||
|
||||
export default {
|
||||
mixins: [challengeUtilities],
|
||||
components: {
|
||||
Sidebar,
|
||||
ChallengeItem,
|
||||
challengeModal,
|
||||
MugenScroll,
|
||||
},
|
||||
mixins: [challengeUtilities],
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
@@ -143,13 +143,13 @@ export default {
|
||||
computed: {
|
||||
...mapState({ user: 'user.data' }),
|
||||
filteredChallenges () {
|
||||
const filters = this.filters;
|
||||
const user = this.user;
|
||||
const { filters } = this;
|
||||
const { user } = this;
|
||||
|
||||
return this.challenges.filter(challenge => {
|
||||
let isMember = true;
|
||||
|
||||
let filteringRole = filters.roles && filters.roles.length > 0;
|
||||
const filteringRole = filters.roles && filters.roles.length > 0;
|
||||
if (filteringRole && filters.roles.indexOf('participating') !== -1) {
|
||||
isMember = this.isMemberOfChallenge(user, challenge);
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ import tier9 from '@/assets/svg/tier-staff.svg';
|
||||
import tierNPC from '@/assets/svg/tier-npc.svg';
|
||||
|
||||
export default {
|
||||
mixins: [styleHelper],
|
||||
props: ['selections', 'text', 'caretPosition', 'coords', 'chat', 'textbox'],
|
||||
data () {
|
||||
return {
|
||||
@@ -93,7 +94,7 @@ export default {
|
||||
computed: {
|
||||
autocompleteStyle () {
|
||||
function heightToUse (textBox, topCoords) {
|
||||
let textBoxHeight = textBox['user-entry'].clientHeight;
|
||||
const textBoxHeight = textBox['user-entry'].clientHeight;
|
||||
return topCoords < textBoxHeight ? topCoords + 30 : textBoxHeight + 10;
|
||||
}
|
||||
return {
|
||||
@@ -113,15 +114,10 @@ export default {
|
||||
this.currentSearch = this.atRegex.exec(this.text)[0]; // eslint-disable-line vue/no-side-effects-in-computed-properties
|
||||
this.currentSearch = this.currentSearch.substring(1, this.currentSearch.length); // eslint-disable-line vue/no-side-effects-in-computed-properties
|
||||
|
||||
return this.tmpSelections.filter((option) => {
|
||||
return option.displayName.toLowerCase().indexOf(this.currentSearch.toLowerCase()) !== -1 || option.username && option.username.toLowerCase().indexOf(this.currentSearch.toLowerCase()) !== -1;
|
||||
}).slice(0, 4);
|
||||
return this.tmpSelections.filter(option => option.displayName.toLowerCase().indexOf(this.currentSearch.toLowerCase()) !== -1 || option.username && option.username.toLowerCase().indexOf(this.currentSearch.toLowerCase()) !== -1).slice(0, 4);
|
||||
},
|
||||
|
||||
},
|
||||
mounted () {
|
||||
this.grabUserNames();
|
||||
},
|
||||
watch: {
|
||||
text (newText) {
|
||||
if (!newText[newText.length - 1] || newText[newText.length - 1] === ' ') {
|
||||
@@ -143,6 +139,9 @@ export default {
|
||||
this.grabUserNames();
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.grabUserNames();
|
||||
},
|
||||
methods: {
|
||||
resetDefaults () {
|
||||
// Mounted is not called when switching between group pages because they have the
|
||||
@@ -153,9 +152,9 @@ export default {
|
||||
this.resetSelection();
|
||||
},
|
||||
grabUserNames () {
|
||||
let usersThatMessage = groupBy(this.chat, 'user');
|
||||
for (let userKey in usersThatMessage) {
|
||||
let systemMessage = userKey === 'undefined';
|
||||
const usersThatMessage = groupBy(this.chat, 'user');
|
||||
for (const userKey in usersThatMessage) {
|
||||
const systemMessage = userKey === 'undefined';
|
||||
if (!systemMessage && this.tmpSelections.indexOf(userKey) === -1) {
|
||||
this.tmpSelections.push({
|
||||
displayName: userKey,
|
||||
@@ -204,18 +203,18 @@ export default {
|
||||
selectNext () {
|
||||
if (this.searchResults.length > 0) {
|
||||
this.clearHover();
|
||||
this.selected = this.selected === null ?
|
||||
0 :
|
||||
(this.selected + 1) % this.searchResults.length;
|
||||
this.selected = this.selected === null
|
||||
? 0
|
||||
: (this.selected + 1) % this.searchResults.length;
|
||||
this.searchResults[this.selected].hover = true;
|
||||
}
|
||||
},
|
||||
selectPrevious () {
|
||||
if (this.searchResults.length > 0) {
|
||||
this.clearHover();
|
||||
this.selected = this.selected === null ?
|
||||
this.searchResults.length - 1 :
|
||||
(this.selected - 1 + this.searchResults.length) % this.searchResults.length;
|
||||
this.selected = this.selected === null
|
||||
? this.searchResults.length - 1
|
||||
: (this.selected - 1 + this.searchResults.length) % this.searchResults.length;
|
||||
this.searchResults[this.selected].hover = true;
|
||||
}
|
||||
},
|
||||
@@ -231,6 +230,5 @@ export default {
|
||||
this.resetSelection();
|
||||
},
|
||||
},
|
||||
mixins: [styleHelper],
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -141,6 +141,15 @@ import { CHAT_FLAG_LIMIT_FOR_HIDING, CHAT_FLAG_FROM_SHADOW_MUTE } from '@/../../
|
||||
|
||||
export default {
|
||||
components: { userLink },
|
||||
filters: {
|
||||
timeAgo (value) {
|
||||
return moment(value).fromNow();
|
||||
},
|
||||
date (value) {
|
||||
// @TODO: Vue doesn't support this so we cant user preference
|
||||
return moment(value).toDate().toString();
|
||||
},
|
||||
},
|
||||
props: {
|
||||
msg: {},
|
||||
inbox: {
|
||||
@@ -161,20 +170,11 @@ export default {
|
||||
reported: false,
|
||||
};
|
||||
},
|
||||
filters: {
|
||||
timeAgo (value) {
|
||||
return moment(value).fromNow();
|
||||
},
|
||||
date (value) {
|
||||
// @TODO: Vue doesn't support this so we cant user preference
|
||||
return moment(value).toDate().toString();
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapState({ user: 'user.data' }),
|
||||
isUserMentioned () {
|
||||
const message = this.msg;
|
||||
const user = this.user;
|
||||
const { user } = this;
|
||||
|
||||
if (message.hasOwnProperty('highlight')) return message.highlight;
|
||||
|
||||
@@ -190,7 +190,7 @@ export default {
|
||||
const pattern = `@(${escapedUsername}|${escapedDisplayName})(\\b)`;
|
||||
const precedingChar = messageText.substring(mentioned - 1, mentioned);
|
||||
if (mentioned === 0 || precedingChar.trim() === '' || precedingChar === '@') {
|
||||
let regex = new RegExp(pattern, 'i');
|
||||
const regex = new RegExp(pattern, 'i');
|
||||
message.highlight = regex.test(messageText);
|
||||
}
|
||||
|
||||
@@ -201,8 +201,8 @@ export default {
|
||||
if (!message.likes) return 0;
|
||||
|
||||
let likeCount = 0;
|
||||
for (let key in message.likes) {
|
||||
let like = message.likes[key];
|
||||
for (const key in message.likes) {
|
||||
const like = message.likes[key];
|
||||
if (like) likeCount += 1;
|
||||
}
|
||||
return likeCount;
|
||||
@@ -217,9 +217,14 @@ export default {
|
||||
return 'Message hidden (shadow-muted)';
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.CHAT_FLAG_LIMIT_FOR_HIDING = CHAT_FLAG_LIMIT_FOR_HIDING;
|
||||
this.CHAT_FLAG_FROM_SHADOW_MUTE = CHAT_FLAG_FROM_SHADOW_MUTE;
|
||||
this.$emit('chat-card-mounted', this.msg.id);
|
||||
},
|
||||
methods: {
|
||||
async like () {
|
||||
let message = cloneDeep(this.msg);
|
||||
const message = cloneDeep(this.msg);
|
||||
|
||||
await this.$store.dispatch('chat:like', {
|
||||
groupId: this.groupId,
|
||||
@@ -279,10 +284,5 @@ export default {
|
||||
return habiticaMarkdown.render(String(text));
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
this.CHAT_FLAG_LIMIT_FOR_HIDING = CHAT_FLAG_LIMIT_FOR_HIDING;
|
||||
this.CHAT_FLAG_FROM_SHADOW_MUTE = CHAT_FLAG_FROM_SHADOW_MUTE;
|
||||
this.$emit('chat-card-mounted', this.msg.id);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -140,15 +140,20 @@
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
import axios from 'axios';
|
||||
import { mapState } from '@/libs/store';
|
||||
import debounce from 'lodash/debounce';
|
||||
import findIndex from 'lodash/findIndex';
|
||||
import { mapState } from '@/libs/store';
|
||||
|
||||
import Avatar from '../avatar';
|
||||
import copyAsTodoModal from './copyAsTodoModal';
|
||||
import chatCard from './chatCard';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
copyAsTodoModal,
|
||||
chatCard,
|
||||
Avatar,
|
||||
},
|
||||
props: {
|
||||
chat: {},
|
||||
inbox: {
|
||||
@@ -162,20 +167,6 @@ export default {
|
||||
isLoading: Boolean,
|
||||
canLoadMore: Boolean,
|
||||
},
|
||||
components: {
|
||||
copyAsTodoModal,
|
||||
chatCard,
|
||||
Avatar,
|
||||
},
|
||||
mounted () {
|
||||
this.loadProfileCache();
|
||||
},
|
||||
created () {
|
||||
window.addEventListener('scroll', this.handleScroll);
|
||||
},
|
||||
destroyed () {
|
||||
window.removeEventListener('scroll', this.handleScroll);
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
currentDayDividerDisplay: moment().day(),
|
||||
@@ -187,6 +178,15 @@ export default {
|
||||
lastOffset: -1,
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
this.loadProfileCache();
|
||||
},
|
||||
created () {
|
||||
window.addEventListener('scroll', this.handleScroll);
|
||||
},
|
||||
destroyed () {
|
||||
window.removeEventListener('scroll', this.handleScroll);
|
||||
},
|
||||
computed: {
|
||||
...mapState({ user: 'user.data' }),
|
||||
// @TODO: We need a different lazy load mechnism.
|
||||
@@ -201,7 +201,7 @@ export default {
|
||||
this.loadProfileCache(window.scrollY / 1000);
|
||||
},
|
||||
async triggerLoad () {
|
||||
const container = this.$refs.container;
|
||||
const { container } = this.$refs;
|
||||
|
||||
// get current offset
|
||||
this.lastOffset = container.scrollTop - (container.scrollHeight - container.clientHeight);
|
||||
@@ -226,7 +226,7 @@ export default {
|
||||
if (this.loading) return;
|
||||
this.loading = true;
|
||||
|
||||
let promises = [];
|
||||
const promises = [];
|
||||
const noProfilesLoaded = Object.keys(this.cachedProfileData).length === 0;
|
||||
|
||||
// @TODO: write an explination
|
||||
@@ -237,9 +237,9 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
let aboutToCache = {};
|
||||
const aboutToCache = {};
|
||||
this.messages.forEach(message => {
|
||||
let uuid = message.uuid;
|
||||
const { uuid } = message;
|
||||
|
||||
if (message.userStyles) {
|
||||
this.$set(this.cachedProfileData, uuid, message.userStyles);
|
||||
@@ -253,19 +253,19 @@ export default {
|
||||
}
|
||||
});
|
||||
|
||||
let results = await Promise.all(promises);
|
||||
const results = await Promise.all(promises);
|
||||
results.forEach(result => {
|
||||
// We could not load the user. Maybe they were deleted. So, let's cache empty so we don't try again
|
||||
if (!result || !result.data || result.status >= 400) {
|
||||
return;
|
||||
}
|
||||
|
||||
let userData = result.data.data;
|
||||
const userData = result.data.data;
|
||||
this.$set(this.cachedProfileData, userData._id, userData);
|
||||
});
|
||||
|
||||
// Merge in any attempts that were rejected so we don't attempt again
|
||||
for (let uuid in aboutToCache) {
|
||||
for (const uuid in aboutToCache) {
|
||||
if (!this.cachedProfileData[uuid]) {
|
||||
this.$set(this.cachedProfileData, uuid, { rejected: true });
|
||||
}
|
||||
@@ -293,11 +293,10 @@ export default {
|
||||
type: 'error',
|
||||
timeout: false,
|
||||
});
|
||||
} else {
|
||||
}
|
||||
this.cachedProfileData[memberId] = result.data.data;
|
||||
profile = result.data.data;
|
||||
}
|
||||
}
|
||||
|
||||
// Open the modal only if the data is available
|
||||
if (profile && !profile.rejected) {
|
||||
@@ -308,7 +307,7 @@ export default {
|
||||
if (this.handleScrollBack) {
|
||||
this.handleScrollBack = false;
|
||||
|
||||
const container = this.$refs.container;
|
||||
const { container } = this.$refs;
|
||||
const offset = container.scrollHeight - container.clientHeight;
|
||||
|
||||
const newOffset = offset + this.lastOffset;
|
||||
@@ -319,9 +318,7 @@ export default {
|
||||
}
|
||||
}, 50),
|
||||
messageLiked (message) {
|
||||
const chatIndex = findIndex(this.chat, chatMessage => {
|
||||
return chatMessage.id === message.id;
|
||||
});
|
||||
const chatIndex = findIndex(this.chat, chatMessage => chatMessage.id === message.id);
|
||||
this.chat.splice(chatIndex, 1, message);
|
||||
},
|
||||
messageRemoved (message) {
|
||||
@@ -330,9 +327,7 @@ export default {
|
||||
return;
|
||||
}
|
||||
|
||||
const chatIndex = findIndex(this.chat, chatMessage => {
|
||||
return chatMessage.id === message.id;
|
||||
});
|
||||
const chatIndex = findIndex(this.chat, chatMessage => chatMessage.id === message.id);
|
||||
this.chat.splice(chatIndex, 1);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -59,11 +59,10 @@ export default {
|
||||
groupPath () {
|
||||
if (this.groupId === TAVERN_ID) {
|
||||
return `${baseUrl}/groups/tavern`;
|
||||
} else if (this.groupType === 'party') {
|
||||
} if (this.groupType === 'party') {
|
||||
return `${baseUrl}/party`;
|
||||
} else {
|
||||
return `${baseUrl}/groups/guild/${this.groupId}`;
|
||||
}
|
||||
return `${baseUrl}/groups/guild/${this.groupId}`;
|
||||
},
|
||||
close () {
|
||||
this.$root.$emit('bv::hide::modal', 'copyAsTodo');
|
||||
|
||||
@@ -66,15 +66,15 @@ import notifications from '@/mixins/notifications';
|
||||
import markdownDirective from '@/directives/markdown';
|
||||
|
||||
export default {
|
||||
mixins: [notifications],
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
},
|
||||
mixins: [notifications],
|
||||
computed: {
|
||||
...mapState({ user: 'user.data' }),
|
||||
reportData () {
|
||||
let reportMessage = this.abuseObject.user;
|
||||
let isSystemMessage = this.abuseObject.uuid === 'system';
|
||||
const isSystemMessage = this.abuseObject.uuid === 'system';
|
||||
if (isSystemMessage) reportMessage = this.$t('systemMessage');
|
||||
return {
|
||||
name: `<span class='text-danger'>${reportMessage}</span>`,
|
||||
@@ -82,7 +82,7 @@ export default {
|
||||
},
|
||||
},
|
||||
data () {
|
||||
let abuseFlagModalBody = {
|
||||
const abuseFlagModalBody = {
|
||||
firstLinkStart: '<a href="/static/community-guidelines" target="_blank">',
|
||||
secondLinkStart: '<a href="/static/terms" target="_blank">',
|
||||
linkEnd: '</a>',
|
||||
@@ -108,7 +108,7 @@ export default {
|
||||
async reportAbuse () {
|
||||
this.text(this.$t(this.groupId === 'privateMessage' ? 'pmReported' : 'abuseReported'));
|
||||
|
||||
let result = await this.$store.dispatch('chat:flag', {
|
||||
const result = await this.$store.dispatch('chat:flag', {
|
||||
groupId: this.groupId,
|
||||
chatId: this.abuseObject.id,
|
||||
comment: this.reportComment,
|
||||
|
||||
@@ -736,7 +736,6 @@ import {avatarEditorUtilies} from '../mixins/avatarEditUtilities';
|
||||
import content from '@/../../common/script/content/index';
|
||||
|
||||
export default {
|
||||
mixins: [guide, notifications, avatarEditorUtilies],
|
||||
components: {
|
||||
avatar,
|
||||
toggleSwitch,
|
||||
@@ -748,13 +747,9 @@ export default {
|
||||
|
||||
subMenu,
|
||||
},
|
||||
mounted () {
|
||||
if (this.editing) this.modalPage = 2;
|
||||
// Buy modal is global, so we listen at root. I'd like to not
|
||||
this.$root.$on('buyModal::boughtItem', this.backgroundPurchased);
|
||||
},
|
||||
mixins: [guide, notifications, avatarEditorUtilies],
|
||||
data () {
|
||||
let backgroundShopSets = shops.getBackgroundShopSets();
|
||||
const backgroundShopSets = shops.getBackgroundShopSets();
|
||||
|
||||
return {
|
||||
loading: false,
|
||||
@@ -786,12 +781,10 @@ export default {
|
||||
},
|
||||
],
|
||||
|
||||
bgSubMenuItems: ['2019', '2018', '2017', '2016', '2015', '2014'].map(y =>
|
||||
({
|
||||
bgSubMenuItems: ['2019', '2018', '2017', '2016', '2015', '2014'].map(y => ({
|
||||
id: y,
|
||||
label: y,
|
||||
})
|
||||
),
|
||||
})),
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
@@ -806,6 +799,11 @@ export default {
|
||||
this.$store.state.avatarEditorOptions.subpage = '';
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
if (this.editing) this.modalPage = 2;
|
||||
// Buy modal is global, so we listen at root. I'd like to not
|
||||
this.$root.$on('buyModal::boughtItem', this.backgroundPurchased);
|
||||
},
|
||||
computed: {
|
||||
...mapState({ user: 'user.data' }),
|
||||
|
||||
@@ -818,7 +816,7 @@ export default {
|
||||
},
|
||||
backgroundShopSetsByYear () {
|
||||
// @TODO: add dates to backgrounds
|
||||
let backgroundShopSetsByYear = {
|
||||
const backgroundShopSetsByYear = {
|
||||
2014: [],
|
||||
2015: [],
|
||||
2016: [],
|
||||
@@ -830,12 +828,12 @@ export default {
|
||||
// Hack to force update for now until we restructure the data
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
|
||||
this.backgroundShopSets.forEach((set) => {
|
||||
let year = set.identifier.substr(set.identifier.length - 4);
|
||||
this.backgroundShopSets.forEach(set => {
|
||||
const year = set.identifier.substr(set.identifier.length - 4);
|
||||
if (!backgroundShopSetsByYear[year]) return;
|
||||
|
||||
let setOwnedByUser = false;
|
||||
for (let key in set.items) {
|
||||
for (const key in set.items) {
|
||||
if (this.user.purchased.background[key]) setOwnedByUser = true;
|
||||
}
|
||||
set.userOwns = setOwnedByUser;
|
||||
@@ -845,13 +843,13 @@ export default {
|
||||
return backgroundShopSetsByYear;
|
||||
},
|
||||
ownedBackgrounds () {
|
||||
let ownedBackgrounds = [];
|
||||
const ownedBackgrounds = [];
|
||||
|
||||
// Hack to force update for now until we restructure the data
|
||||
let backgroundUpdate = this.backgroundUpdate; // eslint-disable-line
|
||||
|
||||
this.backgroundShopSets.forEach((set) => {
|
||||
set.items.forEach((bg) => {
|
||||
this.backgroundShopSets.forEach(set => {
|
||||
set.items.forEach(bg => {
|
||||
if (this.user.purchased.background[bg.key]) {
|
||||
ownedBackgrounds.push(bg);
|
||||
}
|
||||
@@ -900,8 +898,8 @@ export default {
|
||||
});
|
||||
|
||||
// @TODO: Move to the action
|
||||
let response = await axios.post('/api/v4/tasks/user', tasksToCreate);
|
||||
let tasks = response.data.data;
|
||||
const response = await axios.post('/api/v4/tasks/user', tasksToCreate);
|
||||
const tasks = response.data.data;
|
||||
tasks.forEach(task => {
|
||||
this.$store.state.user.data.tasksOrder[`${task.type}s`].unshift(task._id);
|
||||
this.$store.state.tasks.data[`${task.type}s`].unshift(task);
|
||||
@@ -926,7 +924,7 @@ export default {
|
||||
let setOwnedByUser = false;
|
||||
|
||||
for (let key in set) {
|
||||
let value = set[key];
|
||||
const value = set[key];
|
||||
if (type === 'background') key = value.key;
|
||||
if (this.user.purchased[type][key]) setOwnedByUser = true;
|
||||
}
|
||||
|
||||
@@ -81,8 +81,8 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
async loadGroup () {
|
||||
let group = await this.$store.dispatch('guilds:getGroup', {groupId: this.groupId});
|
||||
this.group = Object.assign({}, group);
|
||||
const group = await this.$store.dispatch('guilds:getGroup', { groupId: this.groupId });
|
||||
this.group = { ...group };
|
||||
},
|
||||
upgradeGroup () {
|
||||
this.$store.state.upgradingGroup = this.group;
|
||||
|
||||
@@ -79,10 +79,10 @@ import amazonButton from '@/components/payments/amazonButton';
|
||||
import creditCardIcon from '@/assets/svg/credit-card-icon.svg';
|
||||
|
||||
export default {
|
||||
mixins: [paymentsMixin],
|
||||
components: {
|
||||
amazonButton,
|
||||
},
|
||||
mixins: [paymentsMixin],
|
||||
data () {
|
||||
return {
|
||||
amazonPayments: {},
|
||||
@@ -131,7 +131,7 @@ export default {
|
||||
},
|
||||
pay (paymentMethod) {
|
||||
const subscriptionKey = 'group_monthly';
|
||||
let paymentData = {
|
||||
const paymentData = {
|
||||
subscription: subscriptionKey,
|
||||
coupon: null,
|
||||
};
|
||||
|
||||
@@ -22,20 +22,18 @@ import SecondaryMenu from '@/components/secondaryMenu';
|
||||
import { mapState } from '@/libs/store';
|
||||
|
||||
export default {
|
||||
props: ['groupId'],
|
||||
components: {
|
||||
SecondaryMenu,
|
||||
groupFormModal,
|
||||
},
|
||||
props: ['groupId'],
|
||||
computed: {
|
||||
...mapState({
|
||||
user: 'user.data',
|
||||
groupPlans: 'groupPlans',
|
||||
}),
|
||||
currentGroup () {
|
||||
let groupFound = this.groupPlans.find(group => {
|
||||
return group._id === this.groupId;
|
||||
});
|
||||
const groupFound = this.groupPlans.find(group => group._id === this.groupId);
|
||||
|
||||
return groupFound;
|
||||
},
|
||||
|
||||
@@ -67,6 +67,10 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import Vue from 'vue';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import findIndex from 'lodash/findIndex';
|
||||
import groupBy from 'lodash/groupBy';
|
||||
import taskDefaults from '@/../../common/script/libs/taskDefaults';
|
||||
import TaskColumn from '../tasks/column';
|
||||
import TaskModal from '../tasks/taskModal';
|
||||
@@ -80,19 +84,15 @@ import dailyIcon from '@/assets/svg/daily.svg';
|
||||
import todoIcon from '@/assets/svg/todo.svg';
|
||||
import rewardIcon from '@/assets/svg/reward.svg';
|
||||
|
||||
import Vue from 'vue';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import findIndex from 'lodash/findIndex';
|
||||
import groupBy from 'lodash/groupBy';
|
||||
import { mapState } from '@/libs/store';
|
||||
|
||||
export default {
|
||||
props: ['groupId'],
|
||||
components: {
|
||||
TaskColumn,
|
||||
TaskModal,
|
||||
GroupPlanOverviewModal,
|
||||
},
|
||||
props: ['groupId'],
|
||||
data () {
|
||||
return {
|
||||
openCreateBtn: false,
|
||||
@@ -194,22 +194,22 @@ export default {
|
||||
groupId: this.searchId,
|
||||
});
|
||||
|
||||
let members = await this.$store.dispatch('members:getGroupMembers', {groupId: this.searchId});
|
||||
const members = await this.$store.dispatch('members:getGroupMembers', { groupId: this.searchId });
|
||||
this.group.members = members;
|
||||
|
||||
let tasks = await this.$store.dispatch('tasks:getGroupTasks', {
|
||||
const tasks = await this.$store.dispatch('tasks:getGroupTasks', {
|
||||
groupId: this.searchId,
|
||||
});
|
||||
|
||||
let groupedApprovals = await this.loadApprovals();
|
||||
const groupedApprovals = await this.loadApprovals();
|
||||
|
||||
tasks.forEach((task) => {
|
||||
tasks.forEach(task => {
|
||||
if (groupedApprovals[task._id] && groupedApprovals[task._id].length > 0) task.approvals = groupedApprovals[task._id];
|
||||
this.tasksByType[task.type].push(task);
|
||||
});
|
||||
},
|
||||
async loadApprovals () {
|
||||
let approvalRequests = await this.$store.dispatch('tasks:getGroupApprovals', {
|
||||
const approvalRequests = await this.$store.dispatch('tasks:getGroupApprovals', {
|
||||
groupId: this.searchId,
|
||||
});
|
||||
|
||||
@@ -229,10 +229,8 @@ export default {
|
||||
groupId: this.searchId,
|
||||
});
|
||||
|
||||
completedTodos.forEach((task) => {
|
||||
const existingTaskIndex = findIndex(this.tasksByType.todo, (todo) => {
|
||||
return todo._id === task._id;
|
||||
});
|
||||
completedTodos.forEach(task => {
|
||||
const existingTaskIndex = findIndex(this.tasksByType.todo, todo => todo._id === task._id);
|
||||
if (existingTaskIndex === -1) {
|
||||
this.tasksByType.todo.push(task);
|
||||
}
|
||||
@@ -253,15 +251,11 @@ export default {
|
||||
this.tasksByType[task.type].push(task);
|
||||
},
|
||||
taskEdited (task) {
|
||||
let index = findIndex(this.tasksByType[task.type], (taskItem) => {
|
||||
return taskItem._id === task._id;
|
||||
});
|
||||
const index = findIndex(this.tasksByType[task.type], taskItem => taskItem._id === task._id);
|
||||
this.tasksByType[task.type].splice(index, 1, task);
|
||||
},
|
||||
taskDestroyed (task) {
|
||||
let index = findIndex(this.tasksByType[task.type], (taskItem) => {
|
||||
return taskItem._id === task._id;
|
||||
});
|
||||
const index = findIndex(this.tasksByType[task.type], taskItem => taskItem._id === task._id);
|
||||
this.tasksByType[task.type].splice(index, 1);
|
||||
},
|
||||
cancelTaskModal () {
|
||||
@@ -289,12 +283,12 @@ export default {
|
||||
this.closeFilterPanel();
|
||||
},
|
||||
applyFilters () {
|
||||
const temporarilySelectedTags = this.temporarilySelectedTags;
|
||||
const { temporarilySelectedTags } = this;
|
||||
this.selectedTags = temporarilySelectedTags.slice();
|
||||
this.closeFilterPanel();
|
||||
},
|
||||
toggleTag (tag) {
|
||||
const temporarilySelectedTags = this.temporarilySelectedTags;
|
||||
const { temporarilySelectedTags } = this;
|
||||
const tagI = temporarilySelectedTags.indexOf(tag.id);
|
||||
if (tagI === -1) {
|
||||
temporarilySelectedTags.push(tag.id);
|
||||
|
||||
@@ -57,7 +57,6 @@
|
||||
import markdownDirective from '@/directives/markdown';
|
||||
|
||||
export default {
|
||||
props: ['label', 'group', 'placeholder'],
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
},
|
||||
@@ -66,6 +65,7 @@
|
||||
communityGuidelines,
|
||||
chatMessage,
|
||||
},
|
||||
props: ['label', 'group', 'placeholder'],
|
||||
data () {
|
||||
return {
|
||||
newMessage: '',
|
||||
@@ -95,11 +95,11 @@
|
||||
// https://medium.com/@_jh3y/how-to-where-s-the-caret-getting-the-xy-position-of-the-caret-a24ba372990a
|
||||
getCoord (e, text) {
|
||||
this.caretPosition = text.selectionEnd;
|
||||
let div = document.createElement('div');
|
||||
let span = document.createElement('span');
|
||||
let copyStyle = getComputedStyle(text);
|
||||
const div = document.createElement('div');
|
||||
const span = document.createElement('span');
|
||||
const copyStyle = getComputedStyle(text);
|
||||
|
||||
[].forEach.call(copyStyle, (prop) => {
|
||||
[].forEach.call(copyStyle, prop => {
|
||||
div.style[prop] = copyStyle[prop];
|
||||
});
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
this._updateCarretPosition(eventUpdate);
|
||||
}, 250),
|
||||
_updateCarretPosition (eventUpdate) {
|
||||
let text = eventUpdate.target;
|
||||
const text = eventUpdate.target;
|
||||
this.getCoord(eventUpdate, text);
|
||||
},
|
||||
async sendMessageShortcut () {
|
||||
@@ -150,7 +150,7 @@
|
||||
|
||||
// @TODO: I would like to not reload everytime we send. Why are we reloading?
|
||||
// The response has all the necessary data...
|
||||
let chat = await this.$store.dispatch('chat:getChat', {groupId: this.group._id});
|
||||
const chat = await this.$store.dispatch('chat:getChat', { groupId: this.group._id });
|
||||
this.group.chat = chat;
|
||||
},
|
||||
|
||||
|
||||
@@ -159,11 +159,11 @@ b-modal#create-party-modal(size='lg', hide-footer=true)
|
||||
},
|
||||
methods: {
|
||||
async createParty () {
|
||||
let group = {
|
||||
const group = {
|
||||
type: 'party',
|
||||
};
|
||||
group.name = this.$t('possessiveParty', { name: this.user.profile.name });
|
||||
let party = await this.$store.dispatch('guilds:create', {group});
|
||||
const party = await this.$store.dispatch('guilds:create', { group });
|
||||
this.$store.state.party.data = party;
|
||||
this.user.party._id = party._id;
|
||||
|
||||
@@ -179,7 +179,7 @@ b-modal#create-party-modal(size='lg', hide-footer=true)
|
||||
if (navigator.clipboard) {
|
||||
navigator.clipboard.writeText(this.user.auth.local.username);
|
||||
} else {
|
||||
let copyText = document.createElement('textarea');
|
||||
const copyText = document.createElement('textarea');
|
||||
copyText.value = this.user.auth.local.username;
|
||||
document.body.appendChild(copyText);
|
||||
copyText.select();
|
||||
|
||||
@@ -64,7 +64,7 @@ import groupUtilities from '@/mixins/groupsUtilities';
|
||||
import positiveIcon from '@/assets/svg/positive.svg';
|
||||
|
||||
function _mapCategories (guilds) {
|
||||
guilds.forEach((guild) => {
|
||||
guilds.forEach(guild => {
|
||||
if (!guild.categories) return;
|
||||
guild.categorySlugs = guild.categories.map(cat => {
|
||||
if (!cat) return;
|
||||
@@ -74,8 +74,8 @@ function _mapCategories (guilds) {
|
||||
}
|
||||
|
||||
export default {
|
||||
mixins: [groupUtilities],
|
||||
components: { PublicGuildItem, MugenScroll, Sidebar },
|
||||
mixins: [groupUtilities],
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
@@ -113,14 +113,12 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
filteredGuilds () {
|
||||
let search = this.search;
|
||||
let filters = this.filters;
|
||||
let user = this.$store.state.user.data;
|
||||
let filterGuild = this.filterGuild;
|
||||
const { search } = this;
|
||||
const { filters } = this;
|
||||
const user = this.$store.state.user.data;
|
||||
const { filterGuild } = this;
|
||||
// @TODO: Move this to the server
|
||||
return this.guilds.filter((guild) => {
|
||||
return filterGuild(guild, filters, search, user);
|
||||
});
|
||||
return this.guilds.filter(guild => filterGuild(guild, filters, search, user));
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
@@ -133,7 +131,7 @@ export default {
|
||||
|
||||
this.queryFilters.search = eventData.searchTerm;
|
||||
|
||||
let guilds = await this.$store.dispatch('guilds:getPublicGuilds', this.queryFilters);
|
||||
const guilds = await this.$store.dispatch('guilds:getPublicGuilds', this.queryFilters);
|
||||
_mapCategories(guilds);
|
||||
this.guilds = guilds;
|
||||
},
|
||||
@@ -157,7 +155,7 @@ export default {
|
||||
this.queryFilters.categories = eventData.categories.join(',');
|
||||
|
||||
// Role filters
|
||||
let filteringRole = eventData.roles && eventData.roles.length > 0;
|
||||
const filteringRole = eventData.roles && eventData.roles.length > 0;
|
||||
if (filteringRole && eventData.roles.indexOf('member') !== -1) {
|
||||
this.queryFilters.member = true;
|
||||
}
|
||||
@@ -182,7 +180,7 @@ export default {
|
||||
this.queryFilters.maxMemberCount = 99;
|
||||
}
|
||||
|
||||
let guilds = await this.$store.dispatch('guilds:getPublicGuilds', this.queryFilters);
|
||||
const guilds = await this.$store.dispatch('guilds:getPublicGuilds', this.queryFilters);
|
||||
_mapCategories(guilds);
|
||||
this.guilds = guilds;
|
||||
},
|
||||
@@ -194,7 +192,7 @@ export default {
|
||||
|
||||
this.loading = true;
|
||||
this.queryFilters.page = this.lastPageLoaded;
|
||||
let guilds = await this.$store.dispatch('guilds:getPublicGuilds', this.queryFilters);
|
||||
const guilds = await this.$store.dispatch('guilds:getPublicGuilds', this.queryFilters);
|
||||
if (guilds.length === 0) this.hasLoadedAllGuilds = true;
|
||||
|
||||
_mapCategories(guilds);
|
||||
|
||||
@@ -289,8 +289,6 @@ import silverGuildBadgeIcon from '@/assets/svg/silver-guild-badge-small.svg';
|
||||
import bronzeGuildBadgeIcon from '@/assets/svg/bronze-guild-badge-small.svg';
|
||||
|
||||
export default {
|
||||
mixins: [groupUtilities, styleHelper],
|
||||
props: ['groupId'],
|
||||
components: {
|
||||
membersModal,
|
||||
startQuestModal,
|
||||
@@ -307,6 +305,8 @@ export default {
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
},
|
||||
mixins: [groupUtilities, styleHelper],
|
||||
props: ['groupId'],
|
||||
data () {
|
||||
return {
|
||||
searchId: '',
|
||||
@@ -353,16 +353,6 @@ export default {
|
||||
return this.group.memberCount > this.$store.state.constants.LARGE_GROUP_COUNT_MESSAGE_CUTOFF;
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
if (this.isParty) this.searchId = 'party';
|
||||
if (!this.searchId) this.searchId = this.groupId;
|
||||
this.load();
|
||||
},
|
||||
beforeRouteUpdate (to, from, next) {
|
||||
this.$set(this, 'searchId', to.params.groupId);
|
||||
|
||||
next();
|
||||
},
|
||||
watch: {
|
||||
// call again the method if the route changes (when this route is already active)
|
||||
$route: 'fetchGuild',
|
||||
@@ -375,6 +365,16 @@ export default {
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted () {
|
||||
if (this.isParty) this.searchId = 'party';
|
||||
if (!this.searchId) this.searchId = this.groupId;
|
||||
this.load();
|
||||
},
|
||||
beforeRouteUpdate (to, from, next) {
|
||||
this.$set(this, 'searchId', to.params.groupId);
|
||||
|
||||
next();
|
||||
},
|
||||
methods: {
|
||||
acceptCommunityGuidelines () {
|
||||
this.$store.dispatch('user:set', { 'flags.communityGuidelinesAccepted': true });
|
||||
@@ -393,7 +393,7 @@ export default {
|
||||
includeAllPublicFields: true,
|
||||
});
|
||||
this.$root.$on('updatedGroup', group => {
|
||||
let updatedGroup = extend(this.group, group);
|
||||
const updatedGroup = extend(this.group, group);
|
||||
this.$set(this.group, updatedGroup);
|
||||
});
|
||||
},
|
||||
@@ -458,9 +458,7 @@ export default {
|
||||
hasUnreadMessages (groupId) {
|
||||
if (this.user.newMessages[groupId]) return true;
|
||||
|
||||
return this.user.notifications.some(n => {
|
||||
return n.type === 'NEW_CHAT_MESSAGE' && n.data.group.id === groupId;
|
||||
});
|
||||
return this.user.notifications.some(n => n.type === 'NEW_CHAT_MESSAGE' && n.data.group.id === groupId);
|
||||
},
|
||||
checkForAchievements () {
|
||||
// Checks if user's party has reached 2 players for the first time.
|
||||
@@ -493,13 +491,13 @@ export default {
|
||||
|
||||
// @TODO: Get challenges and ask to keep or remove
|
||||
if (!confirm('Are you sure you want to leave?')) return;
|
||||
let keep = true;
|
||||
const keep = true;
|
||||
this.leave(keep);
|
||||
},
|
||||
async leave (keepTasks) {
|
||||
let keepChallenges = 'remain-in-challenges';
|
||||
const keepChallenges = 'remain-in-challenges';
|
||||
|
||||
let data = {
|
||||
const data = {
|
||||
groupId: this.group._id,
|
||||
keep: keepTasks,
|
||||
keepChallenges,
|
||||
|
||||
@@ -185,7 +185,7 @@ export default {
|
||||
markdown: markdownDirective,
|
||||
},
|
||||
data () {
|
||||
let data = {
|
||||
const data = {
|
||||
workingGroup: {
|
||||
id: '',
|
||||
name: '',
|
||||
@@ -267,8 +267,8 @@ export default {
|
||||
membersToInvite: [],
|
||||
};
|
||||
|
||||
let hashedCategories = {};
|
||||
data.categoryOptions.forEach((category) => {
|
||||
const hashedCategories = {};
|
||||
data.categoryOptions.forEach(category => {
|
||||
hashedCategories[category.key] = category.label;
|
||||
});
|
||||
data.categoriesHashByKey = hashedCategories;
|
||||
@@ -286,7 +286,7 @@ export default {
|
||||
return this.$store.state.editingGroup;
|
||||
},
|
||||
charactersRemaining () {
|
||||
let currentLength = this.workingGroup.summary ? this.workingGroup.summary.length : 0;
|
||||
const currentLength = this.workingGroup.summary ? this.workingGroup.summary.length : 0;
|
||||
return MAX_SUMMARY_SIZE_FOR_GUILDS - currentLength;
|
||||
},
|
||||
title () {
|
||||
@@ -304,7 +304,7 @@ export default {
|
||||
},
|
||||
watch: {
|
||||
editingGroup () {
|
||||
let editingGroup = this.editingGroup;
|
||||
const { editingGroup } = this;
|
||||
|
||||
if (!editingGroup._id) {
|
||||
this.resetWorkingGroup();
|
||||
@@ -339,7 +339,7 @@ export default {
|
||||
methods: {
|
||||
async getMembers () {
|
||||
if (!this.workingGroup.id) return;
|
||||
let members = await this.$store.dispatch('members:getGroupMembers', {
|
||||
const members = await this.$store.dispatch('members:getGroupMembers', {
|
||||
groupId: this.workingGroup.id,
|
||||
includeAllPublicFields: true,
|
||||
});
|
||||
@@ -367,7 +367,7 @@ export default {
|
||||
// @TODO return $rootScope.openModal('buyGems', {track:"Gems > Gems > Create Group"});
|
||||
}
|
||||
|
||||
let errors = [];
|
||||
const errors = [];
|
||||
|
||||
if (!this.workingGroup.name) errors.push(this.$t('nameRequired'));
|
||||
if (!this.workingGroup.summary) errors.push(this.$t('summaryRequired'));
|
||||
@@ -391,10 +391,10 @@ export default {
|
||||
challenges: this.workingGroup.onlyLeaderCreatesChallenges,
|
||||
};
|
||||
|
||||
let categoryKeys = this.workingGroup.categories;
|
||||
let serverCategories = [];
|
||||
const categoryKeys = this.workingGroup.categories;
|
||||
const serverCategories = [];
|
||||
categoryKeys.forEach(key => {
|
||||
let catName = this.categoriesHashByKey[key];
|
||||
const catName = this.categoriesHashByKey[key];
|
||||
serverCategories.push({
|
||||
slug: key,
|
||||
name: catName,
|
||||
@@ -402,7 +402,7 @@ export default {
|
||||
});
|
||||
this.workingGroup.categories = serverCategories;
|
||||
|
||||
let groupData = Object.assign({}, this.workingGroup);
|
||||
const groupData = { ...this.workingGroup };
|
||||
|
||||
let newgroup;
|
||||
if (groupData.id) {
|
||||
|
||||
@@ -297,10 +297,10 @@ import creditCardIcon from '@/assets/svg/credit-card-icon.svg';
|
||||
import amazonButton from '@/components/payments/amazonButton';
|
||||
|
||||
export default {
|
||||
mixins: [paymentsMixin],
|
||||
components: {
|
||||
amazonButton,
|
||||
},
|
||||
mixins: [paymentsMixin],
|
||||
data () {
|
||||
return {
|
||||
amazonPayments: {},
|
||||
|
||||
@@ -90,13 +90,13 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { mapState } from '@/libs/store';
|
||||
import clone from 'lodash/clone';
|
||||
import debounce from 'lodash/debounce';
|
||||
import filter from 'lodash/filter';
|
||||
import forEach from 'lodash/forEach';
|
||||
import isEmail from 'validator/lib/isEmail';
|
||||
import isUUID from 'validator/lib/isUUID';
|
||||
import { mapState } from '@/libs/store';
|
||||
import notifications from '@/mixins/notifications';
|
||||
import positiveIcon from '@/assets/svg/positive.svg';
|
||||
|
||||
@@ -106,9 +106,7 @@
|
||||
computed: {
|
||||
...mapState({ user: 'user.data' }),
|
||||
cannotSubmit () {
|
||||
const filteredInvites = filter(this.invites, (invite) => {
|
||||
return invite.text.length > 0 && !invite.valid;
|
||||
});
|
||||
const filteredInvites = filter(this.invites, invite => invite.text.length > 0 && !invite.valid);
|
||||
if (filteredInvites.length > 0) return true;
|
||||
return false;
|
||||
},
|
||||
@@ -126,9 +124,7 @@
|
||||
},
|
||||
methods: {
|
||||
checkInviteList: debounce(function checkList () {
|
||||
this.invites = filter(this.invites, (invite, index) => {
|
||||
return invite.text.length > 0 || index === this.invites.length - 1;
|
||||
});
|
||||
this.invites = filter(this.invites, (invite, index) => invite.text.length > 0 || index === this.invites.length - 1);
|
||||
while (this.invites.length < 2) this.invites.push(clone(INVITE_DEFAULTS));
|
||||
forEach(this.invites, (value, index) => {
|
||||
if (value.text.length < 1 || isEmail(value.text)) {
|
||||
@@ -136,16 +132,12 @@
|
||||
}
|
||||
if (isUUID(value.text)) {
|
||||
this.$store.dispatch('user:userLookup', { uuid: value.text })
|
||||
.then(res => {
|
||||
return this.fillErrors(index, res);
|
||||
});
|
||||
.then(res => this.fillErrors(index, res));
|
||||
} else {
|
||||
let searchUsername = value.text;
|
||||
if (searchUsername[0] === '@') searchUsername = searchUsername.slice(1, searchUsername.length);
|
||||
this.$store.dispatch('user:userLookup', { username: searchUsername })
|
||||
.then(res => {
|
||||
return this.fillErrors(index, res);
|
||||
});
|
||||
.then(res => this.fillErrors(index, res));
|
||||
}
|
||||
});
|
||||
}, 250),
|
||||
@@ -166,13 +158,13 @@
|
||||
this.$root.$emit('bv::hide::modal', 'invite-modal');
|
||||
},
|
||||
async sendInvites () {
|
||||
let invitationDetails = {
|
||||
const invitationDetails = {
|
||||
inviter: this.inviter,
|
||||
emails: [],
|
||||
uuids: [],
|
||||
usernames: [],
|
||||
};
|
||||
forEach(this.invites, (invite) => {
|
||||
forEach(this.invites, invite => {
|
||||
if (invite.text.length < 1) return;
|
||||
if (isEmail(invite.text)) {
|
||||
invitationDetails.emails.push({ email: invite.text });
|
||||
@@ -188,7 +180,7 @@
|
||||
});
|
||||
|
||||
const invitesSent = invitationDetails.emails.length + invitationDetails.uuids.length + invitationDetails.usernames.length;
|
||||
let invitationString = invitesSent > 1 ? 'invitationsSent' : 'invitationSent';
|
||||
const invitationString = invitesSent > 1 ? 'invitationsSent' : 'invitationSent';
|
||||
|
||||
this.text(this.$t(invitationString));
|
||||
this.close();
|
||||
|
||||
@@ -214,11 +214,11 @@ import starIcon from '@/assets/members/star.svg';
|
||||
import dots from '@/assets/svg/dots.svg';
|
||||
|
||||
export default {
|
||||
props: ['hideBadge'],
|
||||
components: {
|
||||
MemberDetails,
|
||||
removeMemberModal,
|
||||
},
|
||||
props: ['hideBadge'],
|
||||
data () {
|
||||
return {
|
||||
sortOption: {},
|
||||
@@ -278,7 +278,7 @@ export default {
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
this.$root.$on('habitica:show-member-modal', (data) => {
|
||||
this.$root.$on('habitica:show-member-modal', data => {
|
||||
// @TODO: Remove store
|
||||
this.$store.state.memberModalOptions.challengeId = data.challengeId;
|
||||
this.$store.state.memberModalOptions.groupId = data.groupId;
|
||||
@@ -370,10 +370,10 @@ export default {
|
||||
});
|
||||
},
|
||||
async getMembers () {
|
||||
let groupId = this.groupId;
|
||||
const { groupId } = this;
|
||||
|
||||
if (groupId && groupId !== 'challenge') {
|
||||
let invites = await this.$store.dispatch('members:getGroupInvites', {
|
||||
const invites = await this.$store.dispatch('members:getGroupInvites', {
|
||||
groupId,
|
||||
includeAllPublicFields: true,
|
||||
});
|
||||
@@ -383,7 +383,7 @@ export default {
|
||||
this.members = this.$store.state.memberModalOptions.viewingMembers;
|
||||
},
|
||||
async clickMember (uid, forceShow) {
|
||||
let user = this.$store.state.user.data;
|
||||
const user = this.$store.state.user.data;
|
||||
|
||||
if (user._id === uid && !forceShow) {
|
||||
if (this.$route.name === 'tasks') {
|
||||
@@ -459,7 +459,7 @@ export default {
|
||||
const lastMember = this.members[this.members.length - 1];
|
||||
if (!lastMember) return;
|
||||
|
||||
let newMembers = await this.$store.state.memberModalOptions.fetchMoreMembers({
|
||||
const newMembers = await this.$store.state.memberModalOptions.fetchMoreMembers({
|
||||
challengeId: this.challengeId,
|
||||
groupId: this.groupId,
|
||||
lastMemberId: lastMember._id,
|
||||
@@ -483,7 +483,7 @@ export default {
|
||||
this.viewMembers();
|
||||
},
|
||||
async promoteToLeader (member) {
|
||||
let groupData = Object.assign({}, this.group);
|
||||
const groupData = { ...this.group };
|
||||
|
||||
groupData.leader = member._id;
|
||||
await this.$store.dispatch('guilds:update', { group: groupData });
|
||||
|
||||
@@ -61,10 +61,10 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import MugenScroll from 'vue-mugen-scroll';
|
||||
import { mapState } from '@/libs/store';
|
||||
import groupUtilities from '@/mixins/groupsUtilities';
|
||||
|
||||
import MugenScroll from 'vue-mugen-scroll';
|
||||
|
||||
import PublicGuildItem from './publicGuildItem';
|
||||
import Sidebar from './sidebar';
|
||||
@@ -73,8 +73,8 @@ import greyBadgeIcon from '@/assets/svg/grey-badge.svg';
|
||||
import positiveIcon from '@/assets/svg/positive.svg';
|
||||
|
||||
export default {
|
||||
mixins: [groupUtilities],
|
||||
components: { PublicGuildItem, MugenScroll, Sidebar },
|
||||
mixins: [groupUtilities],
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
@@ -109,15 +109,13 @@ export default {
|
||||
guilds: 'myGuilds',
|
||||
}),
|
||||
filteredGuilds () {
|
||||
let search = this.search;
|
||||
let filters = this.filters;
|
||||
let user = this.$store.state.user.data;
|
||||
let filterGuild = this.filterGuild;
|
||||
return this.guilds.filter((guild) => {
|
||||
const { search } = this;
|
||||
const { filters } = this;
|
||||
const user = this.$store.state.user.data;
|
||||
const { filterGuild } = this;
|
||||
return this.guilds.filter(guild => {
|
||||
if (guild.categories) {
|
||||
guild.categorySlugs = guild.categories.map(cat => {
|
||||
return cat.slug;
|
||||
});
|
||||
guild.categorySlugs = guild.categories.map(cat => cat.slug);
|
||||
}
|
||||
return filterGuild(guild, filters, search, user);
|
||||
});
|
||||
|
||||
@@ -71,16 +71,16 @@ import { mapGetters } from '@/libs/store';
|
||||
import MemberDetails from '../memberDetails';
|
||||
|
||||
export default {
|
||||
props: ['group'],
|
||||
components: {
|
||||
MemberDetails,
|
||||
},
|
||||
props: ['group'],
|
||||
computed: {
|
||||
...mapGetters({
|
||||
partyMembers: 'party:members',
|
||||
}),
|
||||
participants () {
|
||||
let partyMembers = this.partyMembers || [];
|
||||
const partyMembers = this.partyMembers || [];
|
||||
return partyMembers.filter(member => this.group.quest.members[member._id] === true);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -144,14 +144,14 @@ import bronzeGuildBadgeIcon from '@/assets/svg/bronze-guild-badge-large.svg';
|
||||
import { MAX_SUMMARY_SIZE_FOR_GUILDS } from '@/../../common/script/constants';
|
||||
|
||||
export default {
|
||||
mixins: [groupUtilities],
|
||||
directives: {
|
||||
markdown,
|
||||
},
|
||||
props: ['guild', 'displayLeave', 'displayGemBank'],
|
||||
components: {
|
||||
categoryTags,
|
||||
},
|
||||
mixins: [groupUtilities],
|
||||
props: ['guild', 'displayLeave', 'displayGemBank'],
|
||||
computed: {
|
||||
...mapState({ user: 'user.data' }),
|
||||
isOwner () {
|
||||
@@ -174,9 +174,9 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
showSuggested (guildId) {
|
||||
let habiticaHelpingGuildId = '5481ccf3-5d2d-48a9-a871-70a7380cee5a';
|
||||
let sixtyDaysAgoFromNow = moment().subtract(60, 'days');
|
||||
let isUserNew = moment(this.user.auth.timestamps.created).isAfter(sixtyDaysAgoFromNow);
|
||||
const habiticaHelpingGuildId = '5481ccf3-5d2d-48a9-a871-70a7380cee5a';
|
||||
const sixtyDaysAgoFromNow = moment().subtract(60, 'days');
|
||||
const isUserNew = moment(this.user.auth.timestamps.created).isAfter(sixtyDaysAgoFromNow);
|
||||
return guildId === habiticaHelpingGuildId && isUserNew;
|
||||
},
|
||||
async join () {
|
||||
|
||||
@@ -149,11 +149,11 @@ import questDialogDrops from '../shops/quests/questDialogDrops';
|
||||
import questDialogContent from '../shops/quests/questDialogContent';
|
||||
|
||||
export default {
|
||||
props: ['group'],
|
||||
components: {
|
||||
questDialogDrops,
|
||||
questDialogContent,
|
||||
},
|
||||
props: ['group'],
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
@@ -181,38 +181,36 @@ export default {
|
||||
return quests.quests[this.group.quest.key];
|
||||
},
|
||||
members () {
|
||||
let partyMembers = this.partyMembers || [];
|
||||
return partyMembers.map(member => {
|
||||
return {
|
||||
const partyMembers = this.partyMembers || [];
|
||||
return partyMembers.map(member => ({
|
||||
name: member.profile.name,
|
||||
accepted: this.group.quest.members[member._id],
|
||||
};
|
||||
});
|
||||
}));
|
||||
},
|
||||
canEditQuest () {
|
||||
if (!this.group.quest) return false;
|
||||
let isQuestLeader = this.group.quest.leader === this.user._id;
|
||||
let isPartyLeader = this.group.leader._id === this.user._id;
|
||||
const isQuestLeader = this.group.quest.leader === this.user._id;
|
||||
const isPartyLeader = this.group.leader._id === this.user._id;
|
||||
return isQuestLeader || isPartyLeader;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async questConfirm () {
|
||||
let count = 0;
|
||||
for (let uuid in this.group.quest.members) {
|
||||
for (const uuid in this.group.quest.members) {
|
||||
if (this.group.quest.members[uuid]) count += 1;
|
||||
}
|
||||
if (!confirm(this.$t('questConfirm', { questmembers: count, totalmembers: this.group.memberCount }))) return;
|
||||
this.questForceStart();
|
||||
},
|
||||
async questForceStart () {
|
||||
let quest = await this.$store.dispatch('quests:sendAction', {groupId: this.group._id, action: 'quests/force-start'});
|
||||
const quest = await this.$store.dispatch('quests:sendAction', { groupId: this.group._id, action: 'quests/force-start' });
|
||||
this.group.quest = quest;
|
||||
this.close();
|
||||
},
|
||||
async questCancel () {
|
||||
if (!confirm(this.$t('sureCancel'))) return;
|
||||
let quest = await this.$store.dispatch('quests:sendAction', {groupId: this.group._id, action: 'quests/cancel'});
|
||||
const quest = await this.$store.dispatch('quests:sendAction', { groupId: this.group._id, action: 'quests/cancel' });
|
||||
this.group.quest = quest;
|
||||
this.close();
|
||||
},
|
||||
|
||||
@@ -198,10 +198,10 @@ import sidebarSection from '../sidebarSection';
|
||||
import questIcon from '@/assets/svg/quest.svg';
|
||||
|
||||
export default {
|
||||
props: ['group'],
|
||||
components: {
|
||||
sidebarSection,
|
||||
},
|
||||
props: ['group'],
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
@@ -230,20 +230,20 @@ export default {
|
||||
},
|
||||
canEditQuest () {
|
||||
if (!this.group.quest) return false;
|
||||
let isQuestLeader = this.group.quest.leader === this.user._id;
|
||||
let isPartyLeader = this.group.leader._id === this.user._id;
|
||||
const isQuestLeader = this.group.quest.leader === this.user._id;
|
||||
const isPartyLeader = this.group.leader._id === this.user._id;
|
||||
return isQuestLeader || isPartyLeader;
|
||||
},
|
||||
isMemberOfPendingQuest () {
|
||||
let userid = this.user._id;
|
||||
let group = this.group;
|
||||
const userid = this.user._id;
|
||||
const { group } = this;
|
||||
if (!group.quest || !group.quest.members) return false;
|
||||
if (group.quest.active) return false; // quest is started, not pending
|
||||
return userid in group.quest.members && group.quest.members[userid] !== false;
|
||||
},
|
||||
isMemberOfRunningQuest () {
|
||||
let userid = this.user._id;
|
||||
let group = this.group;
|
||||
const userid = this.user._id;
|
||||
const { group } = this;
|
||||
if (!group.quest || !group.quest.members) return false;
|
||||
if (!group.quest.active) return false; // quest is pending, not started
|
||||
return group.quest.members[userid];
|
||||
@@ -253,7 +253,7 @@ export default {
|
||||
|
||||
if (!this.group || !this.group.quest) return count;
|
||||
|
||||
for (let uuid in this.group.quest.members) {
|
||||
for (const uuid in this.group.quest.members) {
|
||||
if (this.group.quest.members[uuid]) count += 1;
|
||||
}
|
||||
|
||||
@@ -273,20 +273,20 @@ export default {
|
||||
async questAbort () {
|
||||
if (!confirm(this.$t('sureAbort'))) return;
|
||||
if (!confirm(this.$t('doubleSureAbort'))) return;
|
||||
let quest = await this.$store.dispatch('quests:sendAction', {groupId: this.group._id, action: 'quests/abort'});
|
||||
const quest = await this.$store.dispatch('quests:sendAction', { groupId: this.group._id, action: 'quests/abort' });
|
||||
this.group.quest = quest;
|
||||
},
|
||||
async questLeave () {
|
||||
if (!confirm(this.$t('sureLeave'))) return;
|
||||
let quest = await this.$store.dispatch('quests:sendAction', {groupId: this.group._id, action: 'quests/leave'});
|
||||
const quest = await this.$store.dispatch('quests:sendAction', { groupId: this.group._id, action: 'quests/leave' });
|
||||
this.group.quest = quest;
|
||||
},
|
||||
async questAccept (partyId) {
|
||||
let quest = await this.$store.dispatch('quests:sendAction', {groupId: partyId, action: 'quests/accept'});
|
||||
const quest = await this.$store.dispatch('quests:sendAction', { groupId: partyId, action: 'quests/accept' });
|
||||
this.user.party.quest = quest;
|
||||
},
|
||||
async questReject (partyId) {
|
||||
let quest = await this.$store.dispatch('quests:sendAction', {groupId: partyId, action: 'quests/reject'});
|
||||
const quest = await this.$store.dispatch('quests:sendAction', { groupId: partyId, action: 'quests/reject' });
|
||||
this.user.party.quest = quest;
|
||||
},
|
||||
},
|
||||
|
||||
@@ -123,12 +123,12 @@ import questDialogContent from '../shops/quests/questDialogContent';
|
||||
import QuestInfo from '../shops/quests/questInfo';
|
||||
|
||||
export default {
|
||||
props: ['group'],
|
||||
components: {
|
||||
questDialogDrops,
|
||||
questDialogContent,
|
||||
QuestInfo,
|
||||
},
|
||||
props: ['group'],
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
@@ -179,7 +179,7 @@ export default {
|
||||
partySize: this.group.memberCount,
|
||||
});
|
||||
|
||||
let groupId = this.group._id || this.user.party._id;
|
||||
const groupId = this.group._id || this.user.party._id;
|
||||
|
||||
const key = this.selectedQuest;
|
||||
try {
|
||||
|
||||
@@ -119,10 +119,13 @@ import notifications from '@/mixins/notifications';
|
||||
import userLink from '../userLink';
|
||||
|
||||
export default {
|
||||
mixins: [notifications, styleHelper],
|
||||
components: {
|
||||
userLink,
|
||||
},
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
},
|
||||
mixins: [notifications, styleHelper],
|
||||
data () {
|
||||
return {
|
||||
heroes: [],
|
||||
@@ -141,9 +144,6 @@ export default {
|
||||
expandAuth: false,
|
||||
};
|
||||
},
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
},
|
||||
async mounted () {
|
||||
this.heroes = await this.$store.dispatch('hall:getHeroes');
|
||||
},
|
||||
@@ -172,7 +172,7 @@ export default {
|
||||
getFormattedItemReference (pathPrefix, itemKeys, values) {
|
||||
let finishedString = '\n'.concat('path: ', pathPrefix, ', ', 'value: {', values, '}\n');
|
||||
|
||||
each(itemKeys, (key) => {
|
||||
each(itemKeys, key => {
|
||||
finishedString = finishedString.concat('\t', pathPrefix, '.', key, '\n');
|
||||
});
|
||||
|
||||
@@ -180,8 +180,8 @@ export default {
|
||||
},
|
||||
async loadHero (uuid, heroIndex) {
|
||||
this.currentHeroIndex = heroIndex;
|
||||
let hero = await this.$store.dispatch('hall:getHero', { uuid });
|
||||
this.hero = Object.assign({}, hero);
|
||||
const hero = await this.$store.dispatch('hall:getHero', { uuid });
|
||||
this.hero = { ...hero };
|
||||
if (!this.hero.flags) {
|
||||
this.hero.flags = {
|
||||
chatRevoked: false,
|
||||
@@ -192,8 +192,8 @@ export default {
|
||||
this.expandAuth = false;
|
||||
},
|
||||
async saveHero () {
|
||||
this.hero.contributor.admin = this.hero.contributor.level > 7 ? true : false;
|
||||
let heroUpdated = await this.$store.dispatch('hall:updateHero', { heroDetails: this.hero });
|
||||
this.hero.contributor.admin = this.hero.contributor.level > 7;
|
||||
const heroUpdated = await this.$store.dispatch('hall:updateHero', { heroDetails: this.hero });
|
||||
this.text('User updated');
|
||||
this.hero = {};
|
||||
this.heroID = -1;
|
||||
|
||||
@@ -178,7 +178,7 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$root.$on('inviteModal::inviteToGroup', (group) => {
|
||||
this.$root.$on('inviteModal::inviteToGroup', group => {
|
||||
this.inviteModalGroup = group;
|
||||
this.inviteModalGroupType = group.type === 'guild' ? 'Guild' : 'Party';
|
||||
this.$root.$emit('bv::show::modal', 'invite-modal');
|
||||
|
||||
@@ -499,7 +499,7 @@ export default {
|
||||
this.dropdown(click.currentTarget.parentElement);
|
||||
},
|
||||
dropdown (element) {
|
||||
let droppedElement = document.getElementsByClassName('down')[0];
|
||||
const droppedElement = document.getElementsByClassName('down')[0];
|
||||
if (droppedElement && droppedElement !== element) {
|
||||
droppedElement.classList.remove('down');
|
||||
if (droppedElement.lastChild) {
|
||||
|
||||
@@ -14,10 +14,10 @@ base-notification(
|
||||
import BaseNotification from './base';
|
||||
|
||||
export default {
|
||||
props: ['notification', 'canRemove'],
|
||||
components: {
|
||||
BaseNotification,
|
||||
},
|
||||
props: ['notification', 'canRemove'],
|
||||
computed: {
|
||||
cardString () {
|
||||
return this.$t(`${this.notification.data.card}Card`);
|
||||
|
||||
@@ -18,11 +18,11 @@ import { mapState } from '@/libs/store';
|
||||
import sync from '@/mixins/sync';
|
||||
|
||||
export default {
|
||||
mixins: [sync],
|
||||
props: ['notification', 'canRemove'],
|
||||
components: {
|
||||
BaseNotification,
|
||||
},
|
||||
mixins: [sync],
|
||||
props: ['notification', 'canRemove'],
|
||||
computed: {
|
||||
...mapState({ user: 'user.data' }),
|
||||
// Check that the notification has all the necessary data (old ones are missing some fields)
|
||||
@@ -38,9 +38,12 @@ export default {
|
||||
async approve () {
|
||||
// Redirect users to the group tasks page if the notification doesn't have data
|
||||
if (!this.notificationHasData) {
|
||||
this.$router.push({ name: 'groupPlanDetailTaskInformation', params: {
|
||||
this.$router.push({
|
||||
name: 'groupPlanDetailTaskInformation',
|
||||
params: {
|
||||
groupId: this.notification.data.groupId,
|
||||
}});
|
||||
},
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -55,9 +58,12 @@ export default {
|
||||
async needsWork () {
|
||||
// Redirect users to the group tasks page if the notification doesn't have data
|
||||
if (!this.notificationHasData) {
|
||||
this.$router.push({ name: 'groupPlanDetailTaskInformation', params: {
|
||||
this.$router.push({
|
||||
name: 'groupPlanDetailTaskInformation',
|
||||
params: {
|
||||
groupId: this.notification.data.groupId,
|
||||
}});
|
||||
},
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -13,13 +13,13 @@ base-notification(
|
||||
import BaseNotification from './base';
|
||||
|
||||
export default {
|
||||
props: ['notification', 'canRemove'],
|
||||
components: {
|
||||
BaseNotification,
|
||||
},
|
||||
props: ['notification', 'canRemove'],
|
||||
methods: {
|
||||
action () {
|
||||
const groupId = this.notification.data.groupId;
|
||||
const { groupId } = this.notification.data;
|
||||
this.$router.push({ name: 'groupPlanDetailTaskInformation', params: { groupId } });
|
||||
},
|
||||
},
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
import BaseNotification from './base';
|
||||
|
||||
export default {
|
||||
props: ['notification', 'canRemove'],
|
||||
components: {
|
||||
BaseNotification,
|
||||
},
|
||||
props: ['notification', 'canRemove'],
|
||||
methods: {
|
||||
action () {
|
||||
this.$router.push({ name: 'tasks' });
|
||||
|
||||
@@ -13,13 +13,13 @@ base-notification(
|
||||
import BaseNotification from './base';
|
||||
|
||||
export default {
|
||||
props: ['notification', 'canRemove'],
|
||||
components: {
|
||||
BaseNotification,
|
||||
},
|
||||
props: ['notification', 'canRemove'],
|
||||
methods: {
|
||||
action () {
|
||||
const groupId = this.notification.data.groupId;
|
||||
const { groupId } = this.notification.data;
|
||||
this.$router.push({ name: 'groupPlanDetailTaskInformation', params: { groupId } });
|
||||
},
|
||||
},
|
||||
|
||||
@@ -13,10 +13,10 @@ base-notification(
|
||||
import BaseNotification from './base';
|
||||
|
||||
export default {
|
||||
props: ['notification', 'canRemove'],
|
||||
components: {
|
||||
BaseNotification,
|
||||
},
|
||||
props: ['notification', 'canRemove'],
|
||||
methods: {
|
||||
action () {
|
||||
const groupId = this.notification.data.group.id;
|
||||
|
||||
@@ -17,10 +17,10 @@ import BaseNotification from './base';
|
||||
import { mapState } from '@/libs/store';
|
||||
|
||||
export default {
|
||||
props: ['notification', 'canRemove'],
|
||||
components: {
|
||||
BaseNotification,
|
||||
},
|
||||
props: ['notification', 'canRemove'],
|
||||
computed: {
|
||||
...mapState({ user: 'user.data' }),
|
||||
isPublicGuild () {
|
||||
@@ -32,9 +32,8 @@ export default {
|
||||
|
||||
if (this.isPublicGuild) {
|
||||
return this.$t('invitedToPublicGuild', { guild });
|
||||
} else {
|
||||
return this.$t('invitedToPrivateGuild', {guild});
|
||||
}
|
||||
return this.$t('invitedToPrivateGuild', { guild });
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
import BaseNotification from './base';
|
||||
|
||||
export default {
|
||||
props: ['notification', 'canRemove'],
|
||||
components: {
|
||||
BaseNotification,
|
||||
},
|
||||
props: ['notification', 'canRemove'],
|
||||
computed: {
|
||||
achievementString () {
|
||||
return `<strong>${this.$t('achievement')}</strong>: ${this.$t('achievementJustAddWater')}`;
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
import BaseNotification from './base';
|
||||
|
||||
export default {
|
||||
props: ['notification', 'canRemove'],
|
||||
components: {
|
||||
BaseNotification,
|
||||
},
|
||||
props: ['notification', 'canRemove'],
|
||||
computed: {
|
||||
achievementString () {
|
||||
return `<strong>${this.$t('achievement')}</strong>: ${this.$t('achievementLostMasterclasser')}`;
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
import BaseNotification from './base';
|
||||
|
||||
export default {
|
||||
props: ['notification', 'canRemove'],
|
||||
components: {
|
||||
BaseNotification,
|
||||
},
|
||||
props: ['notification', 'canRemove'],
|
||||
computed: {
|
||||
achievementString () {
|
||||
return `<strong>${this.$t('achievement')}</strong>: ${this.$t('achievementMindOverMatter')}`;
|
||||
|
||||
@@ -15,10 +15,10 @@ import BaseNotification from './base';
|
||||
import { mapState } from '@/libs/store';
|
||||
|
||||
export default {
|
||||
props: ['notification', 'canRemove'],
|
||||
components: {
|
||||
BaseNotification,
|
||||
},
|
||||
props: ['notification', 'canRemove'],
|
||||
computed: {
|
||||
...mapState({ user: 'user.data' }),
|
||||
groupId () {
|
||||
|
||||
@@ -15,10 +15,10 @@ base-notification(
|
||||
import BaseNotification from './base';
|
||||
|
||||
export default {
|
||||
props: ['notification', 'canRemove'],
|
||||
components: {
|
||||
BaseNotification,
|
||||
},
|
||||
props: ['notification', 'canRemove'],
|
||||
methods: {
|
||||
action () {
|
||||
this.$root.$emit('bv::show::modal', 'inbox-modal');
|
||||
|
||||
@@ -11,14 +11,14 @@ base-notification(
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import BaseNotification from './base';
|
||||
import moment from 'moment';
|
||||
import BaseNotification from './base';
|
||||
|
||||
export default {
|
||||
props: ['notification', 'canRemove'],
|
||||
components: {
|
||||
BaseNotification,
|
||||
},
|
||||
props: ['notification', 'canRemove'],
|
||||
computed: {
|
||||
mysteryClass () {
|
||||
return `notif_inventory_present_${moment().format('MM')}`;
|
||||
|
||||
@@ -16,10 +16,10 @@ base-notification(
|
||||
import BaseNotification from './base';
|
||||
|
||||
export default {
|
||||
props: ['notification', 'canRemove'],
|
||||
components: {
|
||||
BaseNotification,
|
||||
},
|
||||
props: ['notification', 'canRemove'],
|
||||
methods: {
|
||||
action () {
|
||||
this.$root.$emit('bv::show::modal', 'new-stuff');
|
||||
|
||||
@@ -16,10 +16,10 @@ import BaseNotification from './base';
|
||||
import { mapState } from '@/libs/store';
|
||||
|
||||
export default {
|
||||
props: ['notification', 'canRemove'],
|
||||
components: {
|
||||
BaseNotification,
|
||||
},
|
||||
props: ['notification', 'canRemove'],
|
||||
computed: {
|
||||
...mapState({ user: 'user.data' }),
|
||||
},
|
||||
|
||||
@@ -26,11 +26,11 @@ import * as quests from '@/../../common/script/content/quests';
|
||||
import questInfo from '@/components/shops/quests/questInfo';
|
||||
|
||||
export default {
|
||||
props: ['notification', 'canRemove'],
|
||||
components: {
|
||||
BaseNotification,
|
||||
questInfo,
|
||||
},
|
||||
props: ['notification', 'canRemove'],
|
||||
computed: {
|
||||
...mapState({ user: 'user.data' }),
|
||||
questData () {
|
||||
|
||||
@@ -22,6 +22,9 @@ import BaseNotification from './base';
|
||||
import sparklesIcon from '@/assets/svg/sparkles.svg';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
BaseNotification,
|
||||
},
|
||||
props: ['notification', 'canRemove'],
|
||||
data () {
|
||||
return {
|
||||
@@ -30,9 +33,6 @@ export default {
|
||||
}),
|
||||
};
|
||||
},
|
||||
components: {
|
||||
BaseNotification,
|
||||
},
|
||||
methods: {
|
||||
action () {
|
||||
this.$router.push({ name: 'stats' });
|
||||
|
||||
@@ -46,15 +46,15 @@
|
||||
|
||||
</style>
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import BaseNotification from './base';
|
||||
import { mapState } from '@/libs/store';
|
||||
import axios from 'axios';
|
||||
|
||||
export default {
|
||||
props: ['notification'],
|
||||
components: {
|
||||
BaseNotification,
|
||||
},
|
||||
props: ['notification'],
|
||||
computed: {
|
||||
...mapState({ user: 'user.data' }),
|
||||
},
|
||||
|
||||
@@ -105,12 +105,24 @@ export default {
|
||||
MenuDropdown,
|
||||
MessageCount,
|
||||
// One component for each type
|
||||
NEW_STUFF, GROUP_TASK_NEEDS_WORK,
|
||||
GUILD_INVITATION, PARTY_INVITATION, CHALLENGE_INVITATION,
|
||||
QUEST_INVITATION, GROUP_TASK_APPROVAL, GROUP_TASK_APPROVED, GROUP_TASK_ASSIGNED, GROUP_TASK_CLAIMED,
|
||||
UNALLOCATED_STATS_POINTS, NEW_MYSTERY_ITEMS, CARD_RECEIVED,
|
||||
NEW_INBOX_MESSAGE, NEW_CHAT_MESSAGE,
|
||||
ACHIEVEMENT_JUST_ADD_WATER, ACHIEVEMENT_LOST_MASTERCLASSER, ACHIEVEMENT_MIND_OVER_MATTER,
|
||||
NEW_STUFF,
|
||||
GROUP_TASK_NEEDS_WORK,
|
||||
GUILD_INVITATION,
|
||||
PARTY_INVITATION,
|
||||
CHALLENGE_INVITATION,
|
||||
QUEST_INVITATION,
|
||||
GROUP_TASK_APPROVAL,
|
||||
GROUP_TASK_APPROVED,
|
||||
GROUP_TASK_ASSIGNED,
|
||||
GROUP_TASK_CLAIMED,
|
||||
UNALLOCATED_STATS_POINTS,
|
||||
NEW_MYSTERY_ITEMS,
|
||||
CARD_RECEIVED,
|
||||
NEW_INBOX_MESSAGE,
|
||||
NEW_CHAT_MESSAGE,
|
||||
ACHIEVEMENT_JUST_ADD_WATER,
|
||||
ACHIEVEMENT_LOST_MASTERCLASSER,
|
||||
ACHIEVEMENT_MIND_OVER_MATTER,
|
||||
WorldBoss: WORLD_BOSS,
|
||||
VERIFY_USERNAME,
|
||||
},
|
||||
@@ -157,24 +169,20 @@ export default {
|
||||
const notifications = [];
|
||||
|
||||
// Parties invitations
|
||||
notifications.push(...this.user.invitations.parties.map(partyInvitation => {
|
||||
return {
|
||||
notifications.push(...this.user.invitations.parties.map(partyInvitation => ({
|
||||
type: 'PARTY_INVITATION',
|
||||
data: partyInvitation,
|
||||
// Create a custom id for notifications outside user.notifications (must be unique)
|
||||
id: `custom-party-invitation-${partyInvitation.id}`,
|
||||
};
|
||||
}));
|
||||
})));
|
||||
|
||||
// Guilds invitations
|
||||
notifications.push(...this.user.invitations.guilds.map(guildInvitation => {
|
||||
return {
|
||||
notifications.push(...this.user.invitations.guilds.map(guildInvitation => ({
|
||||
type: 'GUILD_INVITATION',
|
||||
data: guildInvitation,
|
||||
// Create a custom id for notifications outside user.notifications (must be unique)
|
||||
id: `custom-guild-invitation-${guildInvitation.id}`,
|
||||
};
|
||||
}));
|
||||
})));
|
||||
|
||||
// Quest invitation
|
||||
if (this.user.party.quest.RSVPNeeded === true) {
|
||||
@@ -228,9 +236,7 @@ export default {
|
||||
return this.notifications.length;
|
||||
},
|
||||
hasUnseenNotifications () {
|
||||
return this.notifications.some((notification) => {
|
||||
return notification.seen === false ? true : false;
|
||||
});
|
||||
return this.notifications.some(notification => (notification.seen === false));
|
||||
},
|
||||
hasClass () {
|
||||
return this.$store.getters['members:hasClass'](this.user);
|
||||
|
||||
@@ -66,11 +66,11 @@ menu-dropdown.item-user(:right="true")
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import { mapState } from '@/libs/store';
|
||||
import * as Analytics from '@/libs/analytics';
|
||||
import userIcon from '@/assets/svg/user.svg';
|
||||
import MenuDropdown from '../ui/customMenuDropdown';
|
||||
import axios from 'axios';
|
||||
import markPMSRead from '@/../../common/script/ops/markPMSRead';
|
||||
import MessageCount from './messageCount';
|
||||
|
||||
|
||||
@@ -23,10 +23,10 @@ div
|
||||
import statsMixin from '@/mixins/stats';
|
||||
|
||||
export default {
|
||||
mixins: [statsMixin],
|
||||
components: {
|
||||
attributesGrid,
|
||||
},
|
||||
mixins: [statsMixin],
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
@@ -40,16 +40,14 @@ div
|
||||
itemText () {
|
||||
if (this.item.text instanceof Function) {
|
||||
return this.item.text();
|
||||
} else {
|
||||
return this.item.text;
|
||||
}
|
||||
return this.item.text;
|
||||
},
|
||||
itemNotes () {
|
||||
if (this.item.notes instanceof Function) {
|
||||
return this.item.notes();
|
||||
} else {
|
||||
return this.item.notes;
|
||||
}
|
||||
return this.item.notes;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -155,16 +155,14 @@
|
||||
itemText () {
|
||||
if (this.item.text instanceof Function) {
|
||||
return this.item.text();
|
||||
} else {
|
||||
return this.item.text;
|
||||
}
|
||||
return this.item.text;
|
||||
},
|
||||
itemNotes () {
|
||||
if (this.item.notes instanceof Function) {
|
||||
return this.item.notes();
|
||||
} else {
|
||||
return this.item.notes;
|
||||
}
|
||||
return this.item.notes;
|
||||
},
|
||||
itemClass () {
|
||||
return this.item.klass || this.item.specialClass;
|
||||
@@ -196,9 +194,8 @@
|
||||
getClassName (classType) {
|
||||
if (classType === 'wizard') {
|
||||
return this.$t('mage');
|
||||
} else {
|
||||
return this.$t(classType);
|
||||
}
|
||||
return this.$t(classType);
|
||||
},
|
||||
},
|
||||
props: {
|
||||
|
||||
@@ -139,14 +139,14 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { mapState } from '@/libs/store';
|
||||
import { CONSTANTS, setLocalSetting, getLocalSetting } from '@/libs/userlocalManager';
|
||||
|
||||
import each from 'lodash/each';
|
||||
import map from 'lodash/map';
|
||||
import throttle from 'lodash/throttle';
|
||||
import _sortBy from 'lodash/sortBy';
|
||||
import _reverse from 'lodash/reverse';
|
||||
import { CONSTANTS, setLocalSetting, getLocalSetting } from '@/libs/userlocalManager';
|
||||
import { mapState } from '@/libs/store';
|
||||
|
||||
import toggleSwitch from '@/components/ui/toggleSwitch';
|
||||
import Item from '@/components/inventory/item';
|
||||
@@ -162,7 +162,7 @@ import EquipGearModal from './equipGearModal';
|
||||
const sortGearTypes = ['sortByName', 'sortByCon', 'sortByPer', 'sortByStr', 'sortByInt'];
|
||||
|
||||
const sortGearTypeMap = {
|
||||
sortByName: (i) => i.text(),
|
||||
sortByName: i => i.text(),
|
||||
sortByCon: 'con',
|
||||
sortByPer: 'per',
|
||||
sortByStr: 'str',
|
||||
@@ -223,7 +223,7 @@ export default {
|
||||
this.$store.state.equipmentDrawerOpen = false;
|
||||
}
|
||||
|
||||
this.costumeMode = getLocalSetting(CONSTANTS.keyConstants.CURRENT_EQUIPMENT_DRAWER_TAB) === CONSTANTS.equipmentDrawerTabValues.COSTUME_TAB ? true : false;
|
||||
this.costumeMode = getLocalSetting(CONSTANTS.keyConstants.CURRENT_EQUIPMENT_DRAWER_TAB) === CONSTANTS.equipmentDrawerTabValues.COSTUME_TAB;
|
||||
},
|
||||
methods: {
|
||||
selectDrawerTab (tabName) {
|
||||
@@ -255,12 +255,12 @@ export default {
|
||||
});
|
||||
},
|
||||
sortItems (items, sortBy) {
|
||||
let userClass = this.user.stats.class;
|
||||
const userClass = this.user.stats.class;
|
||||
|
||||
return sortBy === 'sortByName' ?
|
||||
_sortBy(items, sortGearTypeMap[sortBy]) :
|
||||
_reverse(_sortBy(items, (item) => {
|
||||
let attrToSort = sortGearTypeMap[sortBy];
|
||||
return sortBy === 'sortByName'
|
||||
? _sortBy(items, sortGearTypeMap[sortBy])
|
||||
: _reverse(_sortBy(items, item => {
|
||||
const attrToSort = sortGearTypeMap[sortBy];
|
||||
let attrValue = item[attrToSort];
|
||||
if (item.klass === userClass || item.specialClass === userClass) {
|
||||
attrValue *= 1.5;
|
||||
@@ -312,11 +312,11 @@ export default {
|
||||
const isSearched = !searchText || ownedItem.text().toLowerCase().indexOf(searchText) !== -1;
|
||||
|
||||
if (ownedItem.klass !== 'base' && isSearched) {
|
||||
const type = ownedItem.type;
|
||||
const { type } = ownedItem;
|
||||
const isEquipped = this.activeItems[type] === ownedItem.key;
|
||||
const viewOptions = this.viewOptions[type];
|
||||
const firstRender = viewOptions.firstRender;
|
||||
const itemsInFirstPosition = viewOptions.itemsInFirstPosition;
|
||||
const { firstRender } = viewOptions;
|
||||
const { itemsInFirstPosition } = viewOptions;
|
||||
|
||||
// Render selected items in first postion only for the first render
|
||||
if (itemsInFirstPosition.indexOf(ownedItem.key) !== -1 && firstRender === false) {
|
||||
@@ -348,15 +348,15 @@ export default {
|
||||
each(this.ownedItems, (isOwned, gearKey) => {
|
||||
if (isOwned === true) {
|
||||
const ownedItem = this.flatGear[gearKey];
|
||||
const klass = ownedItem.klass;
|
||||
const { klass } = ownedItem;
|
||||
|
||||
const isSearched = !searchText || ownedItem.text().toLowerCase().indexOf(searchText) !== -1;
|
||||
|
||||
if (klass !== 'base' && isSearched) {
|
||||
const isEquipped = this.activeItems[ownedItem.type] === ownedItem.key;
|
||||
const viewOptions = this.viewOptions[klass];
|
||||
const firstRender = viewOptions.firstRender;
|
||||
const itemsInFirstPosition = viewOptions.itemsInFirstPosition;
|
||||
const { firstRender } = viewOptions;
|
||||
const { itemsInFirstPosition } = viewOptions;
|
||||
|
||||
// Render selected items in first postion only for the first render
|
||||
if (itemsInFirstPosition.indexOf(ownedItem.key) !== -1 && firstRender === false) {
|
||||
|
||||
@@ -22,10 +22,10 @@ import { mapState } from '@/libs/store';
|
||||
import markdown from '@/directives/markdown';
|
||||
|
||||
export default {
|
||||
props: ['cardOptions'],
|
||||
directives: {
|
||||
markdown,
|
||||
},
|
||||
props: ['cardOptions'],
|
||||
computed: {
|
||||
...mapState({
|
||||
user: 'user.data',
|
||||
@@ -41,13 +41,13 @@ export default {
|
||||
return numberOfVariations;
|
||||
},
|
||||
cardMessage () {
|
||||
let random = Math.random() * this.numberOfVariations;
|
||||
let selection = Math.floor(random);
|
||||
const random = Math.random() * this.numberOfVariations;
|
||||
const selection = Math.floor(random);
|
||||
return this.$t(`${this.cardType}${selection}`);
|
||||
},
|
||||
fromName () {
|
||||
let fromName = '';
|
||||
let card = this.user.items.special[`${this.cardType}Received`];
|
||||
const card = this.user.items.special[`${this.cardType}Received`];
|
||||
if (card && card[0]) fromName = card[0];
|
||||
return fromName;
|
||||
},
|
||||
|
||||
@@ -221,20 +221,17 @@ const groups = [
|
||||
['food', 'Pet_Food_'],
|
||||
['special', 'inventory_special_', allowedSpecialItems],
|
||||
['quests', 'inventory_quest_scroll_'],
|
||||
].map(([group, classPrefix, allowedItems]) => {
|
||||
return {
|
||||
].map(([group, classPrefix, allowedItems]) => ({
|
||||
key: group,
|
||||
quantity: 0,
|
||||
selected: false,
|
||||
classPrefix,
|
||||
allowedItems,
|
||||
};
|
||||
});
|
||||
}));
|
||||
|
||||
let lastMouseMoveEvent = {};
|
||||
|
||||
export default {
|
||||
mixins: [notifications],
|
||||
name: 'Items',
|
||||
components: {
|
||||
Item,
|
||||
@@ -249,6 +246,7 @@ export default {
|
||||
drag: DragDropDirective,
|
||||
mousePosition: MouseMoveDirective,
|
||||
},
|
||||
mixins: [notifications],
|
||||
data () {
|
||||
return {
|
||||
searchText: null,
|
||||
@@ -283,11 +281,11 @@ export default {
|
||||
this.groups.forEach(group => {
|
||||
const groupKey = group.key;
|
||||
group.quantity = 0; // resetf the count
|
||||
let itemsArray = itemsByType[groupKey] = [];
|
||||
const itemsArray = itemsByType[groupKey] = [];
|
||||
const contentItems = this.content[groupKey];
|
||||
|
||||
each(this.user.items[groupKey], (itemQuantity, itemKey) => {
|
||||
let isAllowed = !group.allowedItems || group.allowedItems.indexOf(itemKey) !== -1;
|
||||
const isAllowed = !group.allowedItems || group.allowedItems.indexOf(itemKey) !== -1;
|
||||
|
||||
if (itemQuantity > 0 && isAllowed) {
|
||||
const item = contentItems[itemKey];
|
||||
@@ -310,13 +308,12 @@ export default {
|
||||
itemsArray.sort((a, b) => {
|
||||
if (this.sortBy === 'quantity') {
|
||||
return b.quantity - a.quantity;
|
||||
} else { // AZ
|
||||
} // AZ
|
||||
return a.text.localeCompare(b.text);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
let specialArray = itemsByType.special;
|
||||
const specialArray = itemsByType.special;
|
||||
|
||||
specialArray.push({
|
||||
key: 'mysteryItem',
|
||||
@@ -325,8 +322,8 @@ export default {
|
||||
quantity: this.user.purchased.plan.mysteryItems.length,
|
||||
});
|
||||
|
||||
for (let type in this.content.cardTypes) {
|
||||
let card = this.user.items.special[`${type}Received`] || [];
|
||||
for (const type in this.content.cardTypes) {
|
||||
const card = this.user.items.special[`${type}Received`] || [];
|
||||
if (this.user.items.special[type] > 0 || card.length > 0) {
|
||||
specialArray.push({
|
||||
type: 'card',
|
||||
@@ -347,9 +344,9 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
userHasPet (potionKey, eggKey) {
|
||||
let animalKey = `${eggKey}-${potionKey}`;
|
||||
const animalKey = `${eggKey}-${potionKey}`;
|
||||
|
||||
let result = this.user.items.pets[animalKey] > 0;
|
||||
const result = this.user.items.pets[animalKey] > 0;
|
||||
|
||||
return result;
|
||||
},
|
||||
@@ -367,23 +364,21 @@ export default {
|
||||
// Dragging needs to be added for egg items
|
||||
this.currentDraggingPotion = potion;
|
||||
|
||||
let itemRef = this.$refs.draggingPotionInfo;
|
||||
const itemRef = this.$refs.draggingPotionInfo;
|
||||
|
||||
let dragEvent = $event.event;
|
||||
const dragEvent = $event.event;
|
||||
|
||||
dragEvent.dataTransfer.setDragImage(itemRef, -20, -20);
|
||||
},
|
||||
isHatchable (potion, egg) {
|
||||
if (potion === null || egg === null)
|
||||
return false;
|
||||
if (potion === null || egg === null) return false;
|
||||
|
||||
const petKey = `${egg.key}-${potion.key}`;
|
||||
|
||||
const petInfo = this.content.petInfo[petKey];
|
||||
|
||||
// Check pet exists and is hatchable
|
||||
if (!petInfo || !petInfo.potion)
|
||||
return false;
|
||||
if (!petInfo || !petInfo.potion) return false;
|
||||
|
||||
return !this.userHasPet(potion.key, egg.key);
|
||||
},
|
||||
@@ -461,13 +456,12 @@ export default {
|
||||
if (item.key === 'timeTravelers') {
|
||||
this.$router.push({ name: 'time' });
|
||||
} else if (item.key === 'mysteryItem') {
|
||||
if (item.quantity === 0)
|
||||
return;
|
||||
if (item.quantity === 0) return;
|
||||
|
||||
let result = await this.$store.dispatch('user:openMysteryItem');
|
||||
const result = await this.$store.dispatch('user:openMysteryItem');
|
||||
|
||||
let openedItem = result.data.data;
|
||||
let text = this.content.gear.flat[openedItem.key].text();
|
||||
const openedItem = result.data.data;
|
||||
const text = this.content.gear.flat[openedItem.key].text();
|
||||
this.drop(this.$t('messageDropMysteryItem', { dropText: text }), openedItem);
|
||||
} else {
|
||||
this.$root.$emit('selectMembersModal::showItem', item);
|
||||
|
||||
@@ -22,11 +22,11 @@ div
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import uuid from 'uuid';
|
||||
import DragDropDirective from '@/directives/dragdrop.directive';
|
||||
|
||||
import CountBadge from '@/components/ui/countBadge';
|
||||
|
||||
import uuid from 'uuid';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
|
||||
@@ -54,14 +54,19 @@ b-modal#hatchedPet-modal(:hide-header="true")
|
||||
import markdownDirective from '@/directives/markdown';
|
||||
|
||||
export default {
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
},
|
||||
props: {
|
||||
hideText: {
|
||||
type: Boolean,
|
||||
},
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
pet: null,
|
||||
};
|
||||
},
|
||||
directives: {
|
||||
markdown: markdownDirective,
|
||||
},
|
||||
mounted () {
|
||||
this.$root.$on('hatchedPet::open', this.openDialog);
|
||||
},
|
||||
@@ -79,10 +84,5 @@ b-modal#hatchedPet-modal(:hide-header="true")
|
||||
this.pet = null;
|
||||
},
|
||||
},
|
||||
props: {
|
||||
hideText: {
|
||||
type: Boolean,
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -64,8 +64,8 @@ import svgClose from '@/assets/svg/close.svg';
|
||||
import petMixin from '@/mixins/petMixin';
|
||||
|
||||
export default {
|
||||
props: ['hatchablePet'],
|
||||
mixins: [petMixin],
|
||||
props: ['hatchablePet'],
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
|
||||
@@ -312,13 +312,13 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { mapState } from '@/libs/store';
|
||||
|
||||
import _each from 'lodash/each';
|
||||
import _sortBy from 'lodash/sortBy';
|
||||
import _filter from 'lodash/filter';
|
||||
import _throttle from 'lodash/throttle';
|
||||
import groupBy from 'lodash/groupBy';
|
||||
import { mapState } from '@/libs/store';
|
||||
|
||||
import Item from '../item';
|
||||
import ItemRows from '@/components/ui/itemRows';
|
||||
@@ -359,7 +359,6 @@
|
||||
let lastMouseMoveEvent = {};
|
||||
|
||||
export default {
|
||||
mixins: [notifications, openedItemRowsMixin, petMixin],
|
||||
components: {
|
||||
PetItem,
|
||||
Item,
|
||||
@@ -382,6 +381,7 @@
|
||||
drag: DragDropDirective,
|
||||
mousePosition: MouseMoveDirective,
|
||||
},
|
||||
mixins: [notifications, openedItemRowsMixin, petMixin],
|
||||
data () {
|
||||
const stableSortState = getLocalSetting(CONSTANTS.keyConstants.STABLE_SORT_STATE) || 'standard';
|
||||
|
||||
@@ -413,7 +413,7 @@
|
||||
},
|
||||
watch: {
|
||||
searchText: _throttle(function throttleSearch () {
|
||||
let search = this.searchText.toLowerCase();
|
||||
const search = this.searchText.toLowerCase();
|
||||
this.searchTextThrottled = search;
|
||||
}, 250),
|
||||
selectedSortBy: {
|
||||
@@ -431,7 +431,7 @@
|
||||
user: 'user.data',
|
||||
}),
|
||||
petGroups () {
|
||||
let petGroups = [
|
||||
const petGroups = [
|
||||
{
|
||||
label: this.$t('filterByStandard'),
|
||||
key: 'standardPets',
|
||||
@@ -473,7 +473,7 @@
|
||||
},
|
||||
];
|
||||
|
||||
petGroups.map((petGroup) => {
|
||||
petGroups.map(petGroup => {
|
||||
this.$set(this.viewOptions, petGroup.key, {
|
||||
selected: false,
|
||||
animalCount: 0,
|
||||
@@ -484,7 +484,7 @@
|
||||
return petGroups;
|
||||
},
|
||||
mountGroups () {
|
||||
let mountGroups = [
|
||||
const mountGroups = [
|
||||
{
|
||||
label: this.$t('filterByStandard'),
|
||||
key: 'standardMounts',
|
||||
@@ -518,7 +518,7 @@
|
||||
},
|
||||
];
|
||||
|
||||
mountGroups.map((mountGroup) => {
|
||||
mountGroups.map(mountGroup => {
|
||||
this.$set(this.viewOptions, mountGroup.key, {
|
||||
selected: false,
|
||||
animalCount: 0,
|
||||
@@ -532,15 +532,11 @@
|
||||
return [
|
||||
{
|
||||
label: this.$t('foodTitle'),
|
||||
items: _filter(this.content.food, f => {
|
||||
return f.key !== 'Saddle' && this.userItems.food[f.key];
|
||||
}),
|
||||
items: _filter(this.content.food, f => f.key !== 'Saddle' && this.userItems.food[f.key]),
|
||||
},
|
||||
{
|
||||
label: this.$t('special'),
|
||||
items: _filter(this.content.food, f => {
|
||||
return f.key === 'Saddle' && this.userItems.food[f.key];
|
||||
}),
|
||||
items: _filter(this.content.food, f => f.key === 'Saddle' && this.userItems.food[f.key]),
|
||||
},
|
||||
];
|
||||
},
|
||||
@@ -553,22 +549,22 @@
|
||||
this.$_openedItemRows_toggleByType(key, !this.$_openedItemRows_isToggled(key));
|
||||
},
|
||||
getAnimalList (animalGroup, type) {
|
||||
let key = animalGroup.key;
|
||||
const { key } = animalGroup;
|
||||
|
||||
this.cachedAnimalList = this.cachedAnimalList || {};
|
||||
if (this.cachedAnimalList[key]) {
|
||||
return this.cachedAnimalList[key];
|
||||
}
|
||||
|
||||
let animals = [];
|
||||
let userItems = this.userItems;
|
||||
const animals = [];
|
||||
const { userItems } = this;
|
||||
|
||||
switch (key) {
|
||||
case 'specialPets':
|
||||
case 'specialMounts': {
|
||||
_each(animalGroup.petSource.special, (value, specialKey) => {
|
||||
let eggKey = specialKey.split('-')[0];
|
||||
let potionKey = specialKey.split('-')[1];
|
||||
const eggKey = specialKey.split('-')[0];
|
||||
const potionKey = specialKey.split('-')[1];
|
||||
|
||||
animals.push({
|
||||
key: specialKey,
|
||||
@@ -593,8 +589,8 @@
|
||||
}
|
||||
|
||||
default: {
|
||||
_each(animalGroup.petSource.eggs, (egg) => {
|
||||
_each(animalGroup.petSource.potions, (potion) => {
|
||||
_each(animalGroup.petSource.eggs, egg => {
|
||||
_each(animalGroup.petSource.potions, potion => {
|
||||
animals.push(createAnimal(egg, potion, type, this.content, userItems));
|
||||
});
|
||||
});
|
||||
@@ -607,19 +603,15 @@
|
||||
},
|
||||
listAnimals (animalGroup, type, hideMissing, sort, searchText) {
|
||||
let animals = this.getAnimalList(animalGroup, type);
|
||||
let isPetList = type === 'pet';
|
||||
const isPetList = type === 'pet';
|
||||
|
||||
// 1. Filter
|
||||
if (hideMissing) {
|
||||
animals = _filter(animals, (a) => {
|
||||
return a.isOwned();
|
||||
});
|
||||
animals = _filter(animals, a => a.isOwned());
|
||||
}
|
||||
|
||||
if (searchText && searchText !== '') {
|
||||
animals = _filter(animals, (a) => {
|
||||
return a.name.toLowerCase().indexOf(searchText) !== -1;
|
||||
});
|
||||
animals = _filter(animals, a => a.name.toLowerCase().indexOf(searchText) !== -1);
|
||||
}
|
||||
|
||||
// 2. Sort
|
||||
@@ -634,9 +626,7 @@
|
||||
|
||||
case 'sortByHatchable': {
|
||||
if (isPetList) {
|
||||
let sortFunc = (i) => {
|
||||
return i.isHatchable() ? 0 : 1;
|
||||
};
|
||||
const sortFunc = i => (i.isHatchable() ? 0 : 1);
|
||||
|
||||
animals = _sortBy(animals, [sortFunc]);
|
||||
}
|
||||
@@ -649,18 +639,17 @@
|
||||
return animals;
|
||||
},
|
||||
countOwnedAnimals (animalGroup, type) {
|
||||
let animals = this.getAnimalList(animalGroup, type);
|
||||
const animals = this.getAnimalList(animalGroup, type);
|
||||
|
||||
let countAll = animals.length;
|
||||
let countOwned = _filter(animals, (a) => {
|
||||
const countAll = animals.length;
|
||||
const countOwned = _filter(animals, a =>
|
||||
// when counting pets, include those that have been raised into mounts
|
||||
return a.isOwned() || a.mountOwned();
|
||||
});
|
||||
a.isOwned() || a.mountOwned());
|
||||
|
||||
return `${countOwned.length}/${countAll}`;
|
||||
},
|
||||
pets (animalGroup, hideMissing, sortBy, searchText) {
|
||||
let pets = this.listAnimals(animalGroup, 'pet', hideMissing, sortBy, searchText);
|
||||
const pets = this.listAnimals(animalGroup, 'pet', hideMissing, sortBy, searchText);
|
||||
|
||||
// Don't group special
|
||||
if (animalGroup.key === 'specialPets' || animalGroup.key === 'wackyPets') {
|
||||
@@ -677,7 +666,7 @@
|
||||
return groupBy(pets, groupKey);
|
||||
},
|
||||
mounts (animalGroup, hideMissing, sortBy, searchText) {
|
||||
let mounts = this.listAnimals(animalGroup, 'mount', hideMissing, sortBy, searchText);
|
||||
const mounts = this.listAnimals(animalGroup, 'mount', hideMissing, sortBy, searchText);
|
||||
|
||||
// Don't group special
|
||||
if (animalGroup.key === 'specialMounts') {
|
||||
@@ -709,9 +698,9 @@
|
||||
onDragStart (ev, food) {
|
||||
this.currentDraggingFood = food;
|
||||
|
||||
let itemRef = this.$refs.dragginFoodInfo;
|
||||
const itemRef = this.$refs.dragginFoodInfo;
|
||||
|
||||
let dragEvent = ev.event;
|
||||
const dragEvent = ev.event;
|
||||
|
||||
dragEvent.dataTransfer.setDragImage(itemRef, -20, -20);
|
||||
},
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user