Compare commits
169 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6581cff8d | ||
|
|
5893d8b9bb | ||
|
|
1550d9b4ee | ||
|
|
ade812b86d | ||
|
|
62e6fbef61 | ||
|
|
67a0f8b65a | ||
|
|
aa432022d3 | ||
|
|
86fb3c1fd1 | ||
|
|
ff2b4add8b | ||
|
|
4ba73dfbec | ||
|
|
e675ea9bd1 | ||
|
|
9c27d86ced | ||
|
|
58ee81adfc | ||
|
|
32c9904a6e | ||
|
|
b86e0a1549 | ||
|
|
154ac9bb38 | ||
|
|
a97060445a | ||
|
|
26b59de1de | ||
|
|
21c8b00ef6 | ||
|
|
c25b7293bb | ||
|
|
15e078cb34 | ||
|
|
f7bb17202b | ||
|
|
213b7696c5 | ||
|
|
fe5c95316b | ||
|
|
54617f8583 | ||
|
|
75c9731ca4 | ||
|
|
31afc45744 | ||
|
|
f6466b161b | ||
|
|
a36114e904 | ||
|
|
529f856ab9 | ||
|
|
9077e66973 | ||
|
|
a47a96b70d | ||
|
|
8a94e88786 | ||
|
|
b3aa236d3d | ||
|
|
4dd58ad89e | ||
|
|
317f7ab598 | ||
|
|
d6c47e7e81 | ||
|
|
1ed61a3d3d | ||
|
|
5c734cfa00 | ||
|
|
07f485a654 | ||
|
|
ae76271469 | ||
|
|
c8a8ecbe1f | ||
|
|
fbf69a4a34 | ||
|
|
7f38ffe676 | ||
|
|
a0e0c392e9 | ||
|
|
573e472077 | ||
|
|
955d22278d | ||
|
|
171ee93108 | ||
|
|
5fb0560f0b | ||
|
|
88b616e206 | ||
|
|
08829425cb | ||
|
|
1dbd2bf0dc | ||
|
|
157f98b331 | ||
|
|
3d689837d6 | ||
|
|
2b76bbe0db | ||
|
|
e75db79b50 | ||
|
|
60919671ea | ||
|
|
bca21c1cf0 | ||
|
|
f1993db0fa | ||
|
|
7351c16578 | ||
|
|
5bc8f5dd64 | ||
|
|
20517cd0b2 | ||
|
|
9a4081c54b | ||
|
|
97e0b31a3d | ||
|
|
af17930314 | ||
|
|
094b19f289 | ||
|
|
8e54cef68b | ||
|
|
1df8d5832f | ||
|
|
0542008b7f | ||
|
|
ffa89202e6 | ||
|
|
1203cbbad8 | ||
|
|
f9fb463128 | ||
|
|
ea398f6294 | ||
|
|
5f41042826 | ||
|
|
486b7d4da1 | ||
|
|
91b47e56ff | ||
|
|
9934e59629 | ||
|
|
50cc66d51c | ||
|
|
936c9dc4f3 | ||
|
|
946ade5da1 | ||
|
|
80068a3674 | ||
|
|
d7c9a7874b | ||
|
|
768e5b3f5b | ||
|
|
f3320d9ae3 | ||
|
|
d4538b0909 | ||
|
|
676ee74f19 | ||
|
|
9059f227fa | ||
|
|
6a14d0f3f3 | ||
|
|
3e5c623125 | ||
|
|
e559fb7e4b | ||
|
|
88a1cfb689 | ||
|
|
f12c4e75e6 | ||
|
|
90f08c58cd | ||
|
|
f6aa96c64c | ||
|
|
2b04a1b50c | ||
|
|
7297fb5241 | ||
|
|
98c5a68a8c | ||
|
|
8e643747f8 | ||
|
|
2483e19bee | ||
|
|
f9d3c6ed48 | ||
|
|
09a0e75351 | ||
|
|
644edc5b76 | ||
|
|
a64b994376 | ||
|
|
fb626ebf7e | ||
|
|
dd334f487e | ||
|
|
cd5c86fb69 | ||
|
|
7878761b6f | ||
|
|
d3b63abdd3 | ||
|
|
23fad37205 | ||
|
|
88558e6b98 | ||
|
|
a84ee8497b | ||
|
|
d560ee2da1 | ||
|
|
fd3fce110e | ||
|
|
1bce2b0e28 | ||
|
|
06a59bfe03 | ||
|
|
83a430afad | ||
|
|
949f638b6e | ||
|
|
2b2193e9ce | ||
|
|
0709bada87 | ||
|
|
506586b74c | ||
|
|
99b2ee273f | ||
|
|
aa6e536851 | ||
|
|
2a2c1af7ba | ||
|
|
48e381d702 | ||
|
|
9aafd76746 | ||
|
|
0069af78a3 | ||
|
|
c25fe7eb3d | ||
|
|
b9a9013685 | ||
|
|
54d075e4fd | ||
|
|
1c40044525 | ||
|
|
5784694dc9 | ||
|
|
7af4a6ff11 | ||
|
|
a601be0666 | ||
|
|
1be169a105 | ||
|
|
6b02af69f2 | ||
|
|
1fe4bd2de7 | ||
|
|
afd00a8ab6 | ||
|
|
63918b3c20 | ||
|
|
6293a4b936 | ||
|
|
44502092ad | ||
|
|
ce0e8284fe | ||
|
|
15f104ddd0 | ||
|
|
7f6ae8ffbf | ||
|
|
b2ecfb5a32 | ||
|
|
fa6ba8b668 | ||
|
|
826dffc794 | ||
|
|
688190ac4a | ||
|
|
4909a3b537 | ||
|
|
64e2150f44 | ||
|
|
3f7abc459c | ||
|
|
618cdafd10 | ||
|
|
e7b37d0378 | ||
|
|
3f3e2525d2 | ||
|
|
765e08f999 | ||
|
|
598bc29647 | ||
|
|
39ccddfb1c | ||
|
|
108214a217 | ||
|
|
271f40e355 | ||
|
|
e801547580 | ||
|
|
fc11941186 | ||
|
|
882fad3113 | ||
|
|
6168492711 | ||
|
|
2aade9aaa6 | ||
|
|
4789946c4e | ||
|
|
a69d8877c9 | ||
|
|
7cc0c3bc57 | ||
|
|
fb78495a1b | ||
|
|
22def5111f | ||
|
|
6e91d51def |
30
.github/workflows/test.yml
vendored
@@ -19,7 +19,8 @@ jobs:
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: sudo apt-get -y install libkrb5-dev
|
||||
- run: sudo apt update
|
||||
- run: sudo apt -y install libkrb5-dev
|
||||
- run: cp config.json.example config.json
|
||||
- name: npm install
|
||||
run: |
|
||||
@@ -41,7 +42,8 @@ jobs:
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: sudo apt-get -y install libkrb5-dev
|
||||
- run: sudo apt update
|
||||
- run: sudo apt -y install libkrb5-dev
|
||||
- run: cp config.json.example config.json
|
||||
- name: npm install
|
||||
run: |
|
||||
@@ -63,7 +65,8 @@ jobs:
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: sudo apt-get -y install libkrb5-dev
|
||||
- run: sudo apt update
|
||||
- run: sudo apt -y install libkrb5-dev
|
||||
- run: cp config.json.example config.json
|
||||
- name: npm install
|
||||
run: |
|
||||
@@ -86,7 +89,8 @@ jobs:
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: sudo apt-get -y install libkrb5-dev
|
||||
- run: sudo apt update
|
||||
- run: sudo apt -y install libkrb5-dev
|
||||
- run: cp config.json.example config.json
|
||||
- name: npm install
|
||||
run: |
|
||||
@@ -108,7 +112,8 @@ jobs:
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: sudo apt-get -y install libkrb5-dev
|
||||
- run: sudo apt update
|
||||
- run: sudo apt -y install libkrb5-dev
|
||||
- run: cp config.json.example config.json
|
||||
- name: npm install
|
||||
run: |
|
||||
@@ -137,7 +142,8 @@ jobs:
|
||||
with:
|
||||
mongodb-version: ${{ matrix.mongodb-version }}
|
||||
mongodb-replica-set: rs
|
||||
- run: sudo apt-get -y install libkrb5-dev
|
||||
- run: sudo apt update
|
||||
- run: sudo apt -y install libkrb5-dev
|
||||
- run: cp config.json.example config.json
|
||||
- name: npm install
|
||||
run: |
|
||||
@@ -167,7 +173,8 @@ jobs:
|
||||
with:
|
||||
mongodb-version: ${{ matrix.mongodb-version }}
|
||||
mongodb-replica-set: rs
|
||||
- run: sudo apt-get -y install libkrb5-dev
|
||||
- run: sudo apt update
|
||||
- run: sudo apt -y install libkrb5-dev
|
||||
- run: cp config.json.example config.json
|
||||
- name: npm install
|
||||
run: |
|
||||
@@ -197,7 +204,8 @@ jobs:
|
||||
with:
|
||||
mongodb-version: ${{ matrix.mongodb-version }}
|
||||
mongodb-replica-set: rs
|
||||
- run: sudo apt-get -y install libkrb5-dev
|
||||
- run: sudo apt update
|
||||
- run: sudo apt -y install libkrb5-dev
|
||||
- run: cp config.json.example config.json
|
||||
- name: npm install
|
||||
run: |
|
||||
@@ -222,7 +230,8 @@ jobs:
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: sudo apt-get -y install libkrb5-dev
|
||||
- run: sudo apt update
|
||||
- run: sudo apt -y install libkrb5-dev
|
||||
- run: cp config.json.example config.json
|
||||
- name: npm install
|
||||
run: |
|
||||
@@ -246,7 +255,8 @@ jobs:
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: sudo apt-get -y install libkrb5-dev
|
||||
- run: sudo apt update
|
||||
- run: sudo apt -y install libkrb5-dev
|
||||
- run: cp config.json.example config.json
|
||||
- name: npm install
|
||||
run: |
|
||||
|
||||
25
.heroku/report_deploy.sh
Executable file
@@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
|
||||
DEVELOPER="someone"
|
||||
if git rev-parse --git-dir > /dev/null 2>&1; then
|
||||
DEVELOPERS=$(git log -5 --pretty=format:'%an')
|
||||
IFS=$'\n'
|
||||
DEVELOPER=""
|
||||
for dev in $DEVELOPERS
|
||||
do
|
||||
if [ "$DEVELOPER" == "someone" ]; then
|
||||
if [[ ${dev} != *"[bot]"* ]]; then
|
||||
DEVELOPER=$dev
|
||||
continue
|
||||
fi
|
||||
continue
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
PARTS=$(cut -d"." -f1 <<< $BASE_URL)
|
||||
SERVER_NAME=$(cut -d"/" -f3 <<< ${PARTS[0]})
|
||||
|
||||
SERVER_NAME=":$SERVER_EMOJI: $SERVER_NAME"
|
||||
|
||||
wget $SLACK_DEPLOY_URL --post-data="{\"server_name\": \"$SERVER_NAME\", \"developer\": \"$DEVELOPER\", \"base_url\": \"$BASE_URL\"}" -O /dev/null
|
||||
@@ -37,6 +37,7 @@
|
||||
"NODE_DB_URI": "mongodb://localhost:27017/habitica-dev?replicaSet=rs",
|
||||
"TEST_DB_URI": "mongodb://localhost:27017/habitica-test?replicaSet=rs",
|
||||
"MONGODB_POOL_SIZE": "10",
|
||||
"MONGODB_SOCKET_TIMEOUT": "20000",
|
||||
"NODE_ENV": "development",
|
||||
"PATH": "bin:node_modules/.bin:/usr/local/bin:/usr/bin:/bin",
|
||||
"PAYPAL_BILLING_PLANS_basic_12mo": "basic_12mo",
|
||||
|
||||
@@ -22,7 +22,8 @@ services:
|
||||
dockerfile: ./Dockerfile-Dev
|
||||
command: ["npm", "start"]
|
||||
depends_on:
|
||||
- mongo
|
||||
mongo:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
- NODE_DB_URI=mongodb://mongo/habitrpg
|
||||
networks:
|
||||
@@ -33,7 +34,16 @@ services:
|
||||
- .:/usr/src/habitica
|
||||
- /usr/src/habitica/node_modules
|
||||
mongo:
|
||||
image: mongo:3.6
|
||||
image: mongo:5.0.23
|
||||
restart: unless-stopped
|
||||
command: ["--replSet", "rs", "--bind_ip_all", "--port", "27017"]
|
||||
healthcheck:
|
||||
test: echo "try { rs.status() } catch (err) { rs.initiate() }" | mongosh --port 27017 --quiet
|
||||
interval: 10s
|
||||
timeout: 30s
|
||||
start_period: 0s
|
||||
start_interval: 1s
|
||||
retries: 30
|
||||
networks:
|
||||
- habitica
|
||||
ports:
|
||||
|
||||
@@ -42,10 +42,41 @@ function cssVarMap (sprite) {
|
||||
}
|
||||
}
|
||||
|
||||
function createSpritesStream (name, src) {
|
||||
function filterFile (file) {
|
||||
if (file.relative.indexOf('Mount_Icon_') !== -1) {
|
||||
return false;
|
||||
}
|
||||
if (file.path.indexOf('shop/') !== -1) {
|
||||
return false;
|
||||
}
|
||||
if (file.path.indexOf('stable/eggs') !== -1) {
|
||||
return false;
|
||||
}
|
||||
if (file.path.indexOf('stable/food') !== -1) {
|
||||
return false;
|
||||
}
|
||||
if (file.path.indexOf('stable/potions') !== -1) {
|
||||
return false;
|
||||
}
|
||||
if (file.relative.indexOf('shop_') === 0) {
|
||||
return false;
|
||||
}
|
||||
if (file.relative.indexOf('icon_background') === 0) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
async function createSpritesStream (name, src) {
|
||||
const stream = mergeStream();
|
||||
// need to import this way bc of weird dependency things
|
||||
// eslint-disable-next-line global-require
|
||||
const filter = require('gulp-filter');
|
||||
|
||||
const f = filter(filterFile);
|
||||
|
||||
const spriteData = gulp.src(src)
|
||||
.pipe(f)
|
||||
.pipe(spritesmith({
|
||||
imgName: `spritesmith-${name}.png`,
|
||||
cssName: `spritesmith-${name}.css`,
|
||||
@@ -63,7 +94,7 @@ function createSpritesStream (name, src) {
|
||||
return stream;
|
||||
}
|
||||
|
||||
gulp.task('sprites:main', () => {
|
||||
gulp.task('sprites:main', async () => {
|
||||
const mainSrc = sync('habitica-images/**/*.png');
|
||||
return createSpritesStream('main', mainSrc);
|
||||
});
|
||||
|
||||
47
migrations/archive/2024/20240806_purge_invite_accepted.js
Normal file
@@ -0,0 +1,47 @@
|
||||
/* eslint-disable no-console */
|
||||
import { model as User } from '../../../website/server/models/user';
|
||||
|
||||
const MIGRATION_NAME = '2024_purge_invite_accepted';
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
async function updateUsers (userIds) {
|
||||
count += userIds.length;
|
||||
if (count % progressCount === 0) console.warn(`${count} ${userIds[0]}`);
|
||||
|
||||
return await User.updateMany(
|
||||
{ _id: { $in: userIds } },
|
||||
{ $pull: { notifications: { type: 'GROUP_INVITE_ACCEPTED' } } },
|
||||
).exec();
|
||||
}
|
||||
|
||||
export default async function processUsers () {
|
||||
let query = {
|
||||
migration: { $ne: MIGRATION_NAME },
|
||||
'notifications.type': 'GROUP_INVITE_ACCEPTED',
|
||||
'auth.timestamps.loggedin': { $gt: new Date('2024-06-25') },
|
||||
};
|
||||
|
||||
while (true) { // eslint-disable-line no-constant-condition
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({ _id: 1 })
|
||||
.select({ _id: 1 })
|
||||
.exec();
|
||||
|
||||
if (users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
break;
|
||||
} else {
|
||||
query._id = {
|
||||
$gt: users[users.length - 1],
|
||||
};
|
||||
}
|
||||
|
||||
const userIds = users.map(user => user._id);
|
||||
|
||||
await updateUsers(userIds); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
};
|
||||
115
migrations/archive/2024/20241119_gem_caps_hourglasses.js
Normal file
@@ -0,0 +1,115 @@
|
||||
/* eslint-disable no-console */
|
||||
const MIGRATION_NAME = '20241119_gem_caps_hourglasses';
|
||||
import { model as User } from '../../../website/server/models/user';
|
||||
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
async function updateUser (user) {
|
||||
count += 1;
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
|
||||
const { consecutive, customerId, dateTerminated, planId } = user.purchased.plan;
|
||||
const isRecurring = customerId !== 'Gift' && !dateTerminated;
|
||||
const updateOp = {
|
||||
$set: {
|
||||
migration: MIGRATION_NAME,
|
||||
'purchased.plan.consecutive.gemCapExtra': Math.max(2 * Math.ceil((consecutive.gemCapExtra + 1) / 2, 26)),
|
||||
},
|
||||
$inc: {},
|
||||
};
|
||||
|
||||
let hourglassBonus = 0;
|
||||
|
||||
if (isRecurring) {
|
||||
await user.updateBalance(
|
||||
5,
|
||||
'admin_update_balance',
|
||||
'',
|
||||
'Subscription Reward Migration',
|
||||
);
|
||||
updateOp.$inc.balance = 5;
|
||||
switch (planId) {
|
||||
case 'basic':
|
||||
case 'basic_earned':
|
||||
case 'group_plan_auto':
|
||||
hourglassBonus = 2;
|
||||
break;
|
||||
case 'basic_3mo':
|
||||
case 'basic_6mo':
|
||||
case 'google_6mo':
|
||||
hourglassBonus = 4;
|
||||
break;
|
||||
case 'basic_12mo':
|
||||
hourglassBonus = 12;
|
||||
updateOp.$set['purchased.plan.hourglassPromoReceived'] = new Date();
|
||||
break;
|
||||
default:
|
||||
hourglassBonus = 0;
|
||||
}
|
||||
|
||||
if (hourglassBonus) {
|
||||
updateOp.$inc['purchased.plan.consecutive.trinkets'] = hourglassBonus;
|
||||
await user.updateHourglasses(
|
||||
hourglassBonus,
|
||||
'admin_update_balance',
|
||||
'',
|
||||
'Subscription Reward Migration',
|
||||
);
|
||||
}
|
||||
updateOp.$push = {
|
||||
notifications: {
|
||||
type: 'ITEM_RECEIVED',
|
||||
data: {
|
||||
icon: 'notif_subscriber_reward',
|
||||
title: 'Thanks for being a subscriber!',
|
||||
text: 'Enjoy these extra Mystic Hourglasses and Gems to celebrate our new benefits.',
|
||||
},
|
||||
seen: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return await User.updateOne(
|
||||
{ _id: user._id },
|
||||
updateOp,
|
||||
).exec();
|
||||
}
|
||||
|
||||
export default async function processUsers () {
|
||||
let query = {
|
||||
migration: { $ne: MIGRATION_NAME },
|
||||
'purchased.plan.customerId': { $exists: true },
|
||||
$or: [
|
||||
{ 'purchased.plan.dateTerminated': { $exists: false } },
|
||||
{ 'purchased.plan.dateTerminated': null },
|
||||
{ 'purchased.plan.dateTerminated': { $gt: new Date() } },
|
||||
],
|
||||
};
|
||||
|
||||
const fields = {
|
||||
_id: 1,
|
||||
purchased: 1,
|
||||
};
|
||||
|
||||
while (true) { // eslint-disable-line no-constant-condition
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({_id: 1})
|
||||
.select(fields)
|
||||
.exec();
|
||||
|
||||
if (users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
break;
|
||||
} else {
|
||||
query._id = {
|
||||
$gt: users[users.length - 1],
|
||||
};
|
||||
}
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
};
|
||||
@@ -26,7 +26,7 @@ async function updateUser (user) {
|
||||
[{ name: 'BASE_URL', content: BASE_URL }], // Add variables from template
|
||||
);
|
||||
|
||||
return User.update({ _id: user._id }, { $set: { migration: MIGRATION_NAME } }).exec();
|
||||
return User.updateOne({ _id: user._id }, { $set: { migration: MIGRATION_NAME } }).exec();
|
||||
}
|
||||
|
||||
export default async function processUsers () {
|
||||
|
||||
175
migrations/users/habitoween.js
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Award Habitoween ladder items to participants in this month's Habitoween festivities
|
||||
*/
|
||||
/* eslint-disable no-console */
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
|
||||
const MIGRATION_NAME = '20241030_habitoween_ladder'; // Update when running in future years
|
||||
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
async function updateUser (user) {
|
||||
count += 1;
|
||||
|
||||
const set = { migration: MIGRATION_NAME };
|
||||
const inc = {
|
||||
'items.food.Candy_Skeleton': 1,
|
||||
'items.food.Candy_Base': 1,
|
||||
'items.food.Candy_CottonCandyBlue': 1,
|
||||
'items.food.Candy_CottonCandyPink': 1,
|
||||
'items.food.Candy_Shade': 1,
|
||||
'items.food.Candy_White': 1,
|
||||
'items.food.Candy_Golden': 1,
|
||||
'items.food.Candy_Zombie': 1,
|
||||
'items.food.Candy_Desert': 1,
|
||||
'items.food.Candy_Red': 1,
|
||||
};
|
||||
const push = { notifications: { $each: [] } };
|
||||
|
||||
if (user && user.items && user.items.mounts && user.items.mounts['JackOLantern-RoyalPurple']) {
|
||||
push.notifications.$each.push({
|
||||
type: 'ITEM_RECEIVED',
|
||||
data: {
|
||||
icon: 'notif_habitoween_candy',
|
||||
title: 'Happy Habitoween!',
|
||||
text: 'For this spooky celebration, you\'ve received an assortment of candy for your Pets!',
|
||||
destination: '/inventory/stable',
|
||||
},
|
||||
seen: false,
|
||||
});
|
||||
} else if (user && user.items && user.items.pets && user.items.pets['JackOLantern-RoyalPurple']) {
|
||||
set['items.mounts.JackOLantern-RoyalPurple'] = true;
|
||||
push.notifications.$each.push({
|
||||
type: 'ITEM_RECEIVED',
|
||||
data: {
|
||||
icon: 'notif_habitoween_purple_mount',
|
||||
title: 'Happy Habitoween!',
|
||||
text: 'For this spooky celebration, you\'ve received a Royal Purple Jack-O-Lantern Mount and an assortment of candy for your Pets!',
|
||||
destination: '/inventory/stable',
|
||||
},
|
||||
seen: false,
|
||||
});
|
||||
} else if (user && user.items && user.items.mounts && user.items.mounts['JackOLantern-Glow']) {
|
||||
set['items.pets.JackOLantern-RoyalPurple'] = 5;
|
||||
push.notifications.$each.push({
|
||||
type: 'ITEM_RECEIVED',
|
||||
data: {
|
||||
icon: 'notif_habitoween_purple_pet',
|
||||
title: 'Happy Habitoween!',
|
||||
text: 'For this spooky celebration, you\'ve received a Royal Purple Jack-O-Lantern Pet and an assortment of candy for your Pets!',
|
||||
destination: '/inventory/stable',
|
||||
},
|
||||
seen: false,
|
||||
});
|
||||
} else if (user && user.items && user.items.pets && user.items.pets['JackOLantern-Glow']) {
|
||||
set['items.mounts.JackOLantern-Glow'] = true;
|
||||
push.notifications.$each.push({
|
||||
type: 'ITEM_RECEIVED',
|
||||
data: {
|
||||
icon: 'notif_habitoween_glow_mount',
|
||||
title: 'Happy Habitoween!',
|
||||
text: 'For this spooky celebration, you\'ve received a Glow-in-the-Dark Jack-O-Lantern Mount and an assortment of candy for your Pets!',
|
||||
destination: '/inventory/stable',
|
||||
},
|
||||
seen: false,
|
||||
});
|
||||
} else if (user && user.items && user.items.mounts && user.items.mounts['JackOLantern-Ghost']) {
|
||||
set['items.pets.JackOLantern-Glow'] = 5;
|
||||
push.notifications.$each.push({
|
||||
type: 'ITEM_RECEIVED',
|
||||
data: {
|
||||
icon: 'notif_habitoween_glow_pet',
|
||||
title: 'Happy Habitoween!',
|
||||
text: 'For this spooky celebration, you\'ve received a Glow-in-the-Dark Jack-O-Lantern Pet and an assortment of candy for your Pets!',
|
||||
destination: '/inventory/stable',
|
||||
},
|
||||
seen: false,
|
||||
});
|
||||
} else if (user && user.items && user.items.pets && user.items.pets['JackOLantern-Ghost']) {
|
||||
set['items.mounts.JackOLantern-Ghost'] = true;
|
||||
push.notifications.$each.push({
|
||||
type: 'ITEM_RECEIVED',
|
||||
data: {
|
||||
icon: 'notif_habitoween_ghost_mount',
|
||||
title: 'Happy Habitoween!',
|
||||
text: 'For this spooky celebration, you\'ve received a Ghost Jack-O-Lantern Mount and an assortment of candy for your Pets!',
|
||||
destination: '/inventory/stable',
|
||||
},
|
||||
seen: false,
|
||||
});
|
||||
} else if (user && user.items && user.items.mounts && user.items.mounts['JackOLantern-Base']) {
|
||||
set['items.pets.JackOLantern-Ghost'] = 5;
|
||||
push.notifications.$each.push({
|
||||
type: 'ITEM_RECEIVED',
|
||||
data: {
|
||||
icon: 'notif_habitoween_ghost_pet',
|
||||
title: 'Happy Habitoween!',
|
||||
text: 'For this spooky celebration, you\'ve received a Ghost Jack-O-Lantern Pet and an assortment of candy for your Pets!',
|
||||
destination: '/inventory/stable',
|
||||
},
|
||||
seen: false,
|
||||
});
|
||||
} else if (user && user.items && user.items.pets && user.items.pets['JackOLantern-Base']) {
|
||||
set['items.mounts.JackOLantern-Base'] = true;
|
||||
push.notifications.$each.push({
|
||||
type: 'ITEM_RECEIVED',
|
||||
data: {
|
||||
icon: 'notif_habitoween_base_mount',
|
||||
title: 'Happy Habitoween!',
|
||||
text: 'For this spooky celebration, you\'ve received a Jack-O-Lantern Mount and an assortment of candy for your Pets!',
|
||||
destination: '/inventory/stable',
|
||||
},
|
||||
seen: false,
|
||||
});
|
||||
} else {
|
||||
set['items.pets.JackOLantern-Base'] = 5;
|
||||
push.notifications.$each.push({
|
||||
type: 'ITEM_RECEIVED',
|
||||
data: {
|
||||
icon: 'notif_habitoween_base_pet',
|
||||
title: 'Happy Habitoween!',
|
||||
text: 'For this spooky celebration, you\'ve received a Jack-O-Lantern Pet and an assortment of candy for your Pets!',
|
||||
destination: '/inventory/stable',
|
||||
},
|
||||
seen: false,
|
||||
});
|
||||
}
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
return User.updateOne({ _id: user._id }, { $inc: inc, $push: push, $set: set }).exec();
|
||||
}
|
||||
|
||||
export default async function processUsers () {
|
||||
const query = {
|
||||
migration: { $ne: MIGRATION_NAME },
|
||||
'auth.timestamps.loggedin': { $gt: new Date('2024-10-01') },
|
||||
};
|
||||
|
||||
const fields = {
|
||||
_id: 1,
|
||||
items: 1,
|
||||
};
|
||||
|
||||
while (true) { // eslint-disable-line no-constant-condition
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({ _id: 1 })
|
||||
.select(fields)
|
||||
.lean()
|
||||
.exec();
|
||||
|
||||
if (users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
break;
|
||||
} else {
|
||||
query._id = {
|
||||
$gt: users[users.length - 1],
|
||||
};
|
||||
}
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
}
|
||||
167
migrations/users/harvest_feast.js
Normal file
@@ -0,0 +1,167 @@
|
||||
/* eslint-disable no-console */
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
|
||||
const MIGRATION_NAME = '20241120_harvest_feast';
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
async function updateUser (user) {
|
||||
count += 1;
|
||||
|
||||
const updateOp = {
|
||||
$set: { migration: MIGRATION_NAME },
|
||||
};
|
||||
|
||||
if (typeof user.items.gear.owned.head_special_turkeyHelmGilded !== 'undefined') {
|
||||
updateOp.$inc = {
|
||||
'items.food.Pie_Base': 1,
|
||||
'items.food.Pie_CottonCandyBlue': 1,
|
||||
'items.food.Pie_CottonCandyPink': 1,
|
||||
'items.food.Pie_Desert': 1,
|
||||
'items.food.Pie_Golden': 1,
|
||||
'items.food.Pie_Red': 1,
|
||||
'items.food.Pie_Shade': 1,
|
||||
'items.food.Pie_Skeleton': 1,
|
||||
'items.food.Pie_Zombie': 1,
|
||||
'items.food.Pie_White': 1,
|
||||
};
|
||||
updateOp.$push = {
|
||||
notifications: {
|
||||
type: 'ITEM_RECEIVED',
|
||||
data: {
|
||||
icon: 'notif_harvestfeast_pie',
|
||||
title: 'Happy Harvest Feast!',
|
||||
text: 'Gobble gobble, you\'ve received an assortment of pie for your Pets!',
|
||||
destination: '/inventory/stable',
|
||||
},
|
||||
seen: false,
|
||||
},
|
||||
};
|
||||
} else if (typeof user.items.gear.owned.armor_special_turkeyArmorBase !== 'undefined') {
|
||||
updateOp.$set['items.gear.owned.head_special_turkeyHelmGilded'] = true;
|
||||
updateOp.$set['items.gear.owned.armor_special_turkeyArmorGilded'] = true;
|
||||
updateOp.$set['items.gear.owned.back_special_turkeyTailGilded'] = true;
|
||||
updateOp.$push = {
|
||||
notifications: {
|
||||
type: 'ITEM_RECEIVED',
|
||||
data: {
|
||||
icon: 'notif_harvestfeast_gilded_set',
|
||||
title: 'Happy Harvest Feast!',
|
||||
text: 'Gobble gobble, you\'ve received the Gilded Turkey Armor, Helm, and Tail!',
|
||||
destination: '/inventory/equipment',
|
||||
},
|
||||
seen: false,
|
||||
},
|
||||
};
|
||||
} else if (user.items && user.items.mounts && user.items.mounts['Turkey-Gilded']) {
|
||||
updateOp.$set['items.gear.owned.head_special_turkeyHelmBase'] = true;
|
||||
updateOp.$set['items.gear.owned.armor_special_turkeyArmorBase'] = true;
|
||||
updateOp.$set['items.gear.owned.back_special_turkeyTailBase'] = true;
|
||||
updateOp.$push = {
|
||||
notifications: {
|
||||
type: 'ITEM_RECEIVED',
|
||||
data: {
|
||||
icon: 'notif_harvestfeast_base_set',
|
||||
title: 'Happy Harvest Feast!',
|
||||
text: 'Gobble gobble, you\'ve received the Turkey Armor, Helm, and Tail!',
|
||||
destination: '/inventory/equipment',
|
||||
},
|
||||
seen: false,
|
||||
},
|
||||
};
|
||||
} else if (user.items && user.items.pets && user.items.pets['Turkey-Gilded']) {
|
||||
updateOp.$set['items.mounts.Turkey-Gilded'] = true;
|
||||
updateOp.$push = {
|
||||
notifications: {
|
||||
type: 'ITEM_RECEIVED',
|
||||
data: {
|
||||
icon: 'notif_harvestfeast_gilded_mount',
|
||||
title: 'Happy Harvest Feast!',
|
||||
text: 'Gobble gobble, you\'ve received the Gilded Turkey Mount!',
|
||||
destination: '/inventory/stable',
|
||||
},
|
||||
seen: false,
|
||||
},
|
||||
};
|
||||
} else if (user.items && user.items.mounts && user.items.mounts['Turkey-Base']) {
|
||||
updateOp.$set['items.pets.Turkey-Gilded'] = 5;
|
||||
updateOp.$push = {
|
||||
notifications: {
|
||||
type: 'ITEM_RECEIVED',
|
||||
data: {
|
||||
icon: 'notif_harvestfeast_gilded_pet',
|
||||
title: 'Happy Harvest Feast!',
|
||||
text: 'Gobble gobble, you\'ve received the Gilded Turkey Pet!',
|
||||
destination: '/inventory/stable',
|
||||
},
|
||||
seen: false,
|
||||
},
|
||||
};
|
||||
} else if (user.items && user.items.pets && user.items.pets['Turkey-Base']) {
|
||||
updateOp.$set['items.mounts.Turkey-Base'] = true;
|
||||
updateOp.$push = {
|
||||
notifications: {
|
||||
type: 'ITEM_RECEIVED',
|
||||
data: {
|
||||
icon: 'notif_harvestfeast_base_mount',
|
||||
title: 'Happy Harvest Feast!',
|
||||
text: 'Gobble gobble, you\'ve received the Turkey Mount!',
|
||||
destination: '/inventory/stable',
|
||||
},
|
||||
seen: false,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
updateOp.$set['items.pets.Turkey-Base'] = 5;
|
||||
updateOp.$push = {
|
||||
notifications: {
|
||||
type: 'ITEM_RECEIVED',
|
||||
data: {
|
||||
icon: 'notif_harvestfeast_base_pet',
|
||||
title: 'Happy Harvest Feast!',
|
||||
text: 'Gobble gobble, you\'ve received the Turkey Pet!',
|
||||
destination: '/inventory/stable',
|
||||
},
|
||||
seen: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
|
||||
return User.updateOne({ _id: user._id }, updateOp).exec();
|
||||
}
|
||||
|
||||
export default async function processUsers () {
|
||||
const query = {
|
||||
migration: { $ne: MIGRATION_NAME },
|
||||
'auth.timestamps.loggedin': { $gt: new Date('2024-10-20') },
|
||||
};
|
||||
|
||||
const fields = {
|
||||
_id: 1,
|
||||
items: 1,
|
||||
};
|
||||
|
||||
while (true) { // eslint-disable-line no-constant-condition
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({ _id: 1 })
|
||||
.select(fields)
|
||||
.lean()
|
||||
.exec();
|
||||
|
||||
if (users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
break;
|
||||
} else {
|
||||
query._id = {
|
||||
$gt: users[users.length - 1],
|
||||
};
|
||||
}
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
/* eslint-disable no-console */
|
||||
const MIGRATION_NAME = '20230731_naming_day';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
|
||||
import { model as User } from '../../../website/server/models/user';
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
|
||||
const MIGRATION_NAME = '20240731_naming_day';
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
async function updateUser (user) {
|
||||
count++;
|
||||
count += 1;
|
||||
|
||||
let set;
|
||||
let push;
|
||||
@@ -115,16 +113,16 @@ async function updateUser (user) {
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
|
||||
if (push) {
|
||||
return await user.updateOne({ $set: set, $inc: inc, $push: push }).exec();
|
||||
} else {
|
||||
return await user.updateOne({ $set: set, $inc: inc }).exec();
|
||||
return user.updateOne({ $set: set, $inc: inc, $push: push }).exec();
|
||||
}
|
||||
|
||||
return user.updateOne({ $set: set, $inc: inc }).exec();
|
||||
}
|
||||
|
||||
export default async function processUsers () {
|
||||
let query = {
|
||||
const query = {
|
||||
migration: { $ne: MIGRATION_NAME },
|
||||
'auth.timestamps.loggedin': { $gt: new Date('2023-07-01') },
|
||||
'auth.timestamps.loggedin': { $gt: new Date('2024-07-01') },
|
||||
};
|
||||
|
||||
const fields = {
|
||||
@@ -136,7 +134,7 @@ export default async function processUsers () {
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({_id: 1})
|
||||
.sort({ _id: 1 })
|
||||
.select(fields)
|
||||
.exec();
|
||||
|
||||
@@ -152,4 +150,4 @@ export default async function processUsers () {
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
};
|
||||
}
|
||||
125
migrations/users/nye.js
Normal file
@@ -0,0 +1,125 @@
|
||||
/* eslint-disable no-console */
|
||||
import { model as User } from '../../website/server/models/user';
|
||||
|
||||
const MIGRATION_NAME = '20231228_nye';
|
||||
const progressCount = 1000;
|
||||
let count = 0;
|
||||
|
||||
async function updateUser (user) {
|
||||
count += 1;
|
||||
|
||||
const updateOp = {
|
||||
$set: { migration: MIGRATION_NAME },
|
||||
$push: { },
|
||||
};
|
||||
const data = {
|
||||
title: 'Happy New Year!',
|
||||
destination: '/inventory/equipment',
|
||||
};
|
||||
|
||||
if (typeof user.items.gear.owned.head_special_nye2023 !== 'undefined') {
|
||||
updateOp.$inc = {
|
||||
'items.food.Candy_Skeleton': 1,
|
||||
'items.food.Candy_Base': 1,
|
||||
'items.food.Candy_CottonCandyBlue': 1,
|
||||
'items.food.Candy_CottonCandyPink': 1,
|
||||
'items.food.Candy_Shade': 1,
|
||||
'items.food.Candy_White': 1,
|
||||
'items.food.Candy_Golden': 1,
|
||||
'items.food.Candy_Zombie': 1,
|
||||
'items.food.Candy_Desert': 1,
|
||||
'items.food.Candy_Red': 1,
|
||||
};
|
||||
data.icon = 'notif_candy_nye';
|
||||
data.text = 'You’ve received an assortment of candy to celebrate with your Pets!';
|
||||
data.destination = '/inventory/stable';
|
||||
} else if (typeof user.items.gear.owned.head_special_nye2022 !== 'undefined') {
|
||||
updateOp.$set['items.gear.owned.head_special_nye2023'] = true;
|
||||
data.icon = 'notif_2023hat_nye';
|
||||
data.text = 'Take on your resolutions with style in this Ludicrous Party Hat!';
|
||||
} else if (typeof user.items.gear.owned.head_special_nye2021 !== 'undefined') {
|
||||
updateOp.$set['items.gear.owned.head_special_nye2022'] = true;
|
||||
data.icon = 'notif_2022hat_nye';
|
||||
data.text = 'Take on your resolutions with style in this Fabulous Party Hat!';
|
||||
} else if (typeof user.items.gear.owned.head_special_nye2020 !== 'undefined') {
|
||||
updateOp.$set['items.gear.owned.head_special_nye2021'] = true;
|
||||
data.icon = 'notif_2021hat_nye';
|
||||
data.text = 'Take on your resolutions with style in this Preposterous Party Hat!';
|
||||
} else if (typeof user.items.gear.owned.head_special_nye2019 !== 'undefined') {
|
||||
updateOp.$set['items.gear.owned.head_special_nye2020'] = true;
|
||||
data.icon = 'notif_2020hat_nye';
|
||||
data.text = 'Take on your resolutions with style in this Extravagant Party Hat!';
|
||||
} else if (typeof user.items.gear.owned.head_special_nye2018 !== 'undefined') {
|
||||
updateOp.$set['items.gear.owned.head_special_nye2019'] = true;
|
||||
data.icon = 'notif_2019hat_nye';
|
||||
data.text = 'Take on your resolutions with style in this Outrageous Party Hat!';
|
||||
} else if (typeof user.items.gear.owned.head_special_nye2017 !== 'undefined') {
|
||||
updateOp.$set['items.gear.owned.head_special_nye2018'] = true;
|
||||
data.icon = 'notif_2018hat_nye';
|
||||
data.text = 'Take on your resolutions with style in this Outlandish Party Hat!';
|
||||
} else if (typeof user.items.gear.owned.head_special_nye2016 !== 'undefined') {
|
||||
updateOp.$set['items.gear.owned.head_special_nye2017'] = true;
|
||||
data.icon = 'notif_2017hat_nye';
|
||||
data.text = 'Take on your resolutions with style in this Fanciful Party Hat!';
|
||||
} else if (typeof user.items.gear.owned.head_special_nye2015 !== 'undefined') {
|
||||
updateOp.$set['items.gear.owned.head_special_nye2016'] = true;
|
||||
data.icon = 'notif_2016hat_nye';
|
||||
data.text = 'Take on your resolutions with style in this Whimsical Party Hat!';
|
||||
} else if (typeof user.items.gear.owned.head_special_nye2014 !== 'undefined') {
|
||||
updateOp.$set['items.gear.owned.head_special_nye2015'] = true;
|
||||
data.icon = 'notif_2015hat_nye';
|
||||
data.text = 'Take on your resolutions with style in this Ridiculous Party Hat!';
|
||||
} else if (typeof user.items.gear.owned.head_special_nye !== 'undefined') {
|
||||
updateOp.$set['items.gear.owned.head_special_nye2014'] = true;
|
||||
data.icon = 'notif_2014hat_nye';
|
||||
data.text = 'Take on your resolutions with style in this Silly Party Hat!';
|
||||
} else {
|
||||
updateOp.$set['items.gear.owned.head_special_nye'] = true;
|
||||
data.icon = 'notif_2013hat_nye';
|
||||
data.text = 'Take on your resolutions with style in this Absurd Party Hat!';
|
||||
}
|
||||
|
||||
updateOp.$push.notifications = {
|
||||
type: 'ITEM_RECEIVED',
|
||||
data,
|
||||
seen: false,
|
||||
};
|
||||
|
||||
if (count % progressCount === 0) console.warn(`${count} ${user._id}`);
|
||||
|
||||
return User.updateOne({ _id: user._id }, updateOp).exec();
|
||||
}
|
||||
|
||||
export default async function processUsers () {
|
||||
const query = {
|
||||
'auth.timestamps.loggedin': { $gt: new Date('2023-12-01') },
|
||||
migration: { $ne: MIGRATION_NAME },
|
||||
};
|
||||
|
||||
const fields = {
|
||||
_id: 1,
|
||||
items: 1,
|
||||
};
|
||||
|
||||
while (true) { // eslint-disable-line no-constant-condition
|
||||
const users = await User // eslint-disable-line no-await-in-loop
|
||||
.find(query)
|
||||
.limit(250)
|
||||
.sort({ _id: 1 })
|
||||
.select(fields)
|
||||
.lean()
|
||||
.exec();
|
||||
|
||||
if (users.length === 0) {
|
||||
console.warn('All appropriate users found and modified.');
|
||||
console.warn(`\n${count} users processed\n`);
|
||||
break;
|
||||
} else {
|
||||
query._id = {
|
||||
$gt: users[users.length - 1],
|
||||
};
|
||||
}
|
||||
|
||||
await Promise.all(users.map(updateUser)); // eslint-disable-line no-await-in-loop
|
||||
}
|
||||
}
|
||||
1131
package-lock.json
generated
18
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "habitica",
|
||||
"description": "A habit tracker app which treats your goals like a Role Playing Game.",
|
||||
"version": "5.26.2",
|
||||
"version": "5.32.3",
|
||||
"main": "./website/server/index.js",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.22.10",
|
||||
@@ -15,8 +15,9 @@
|
||||
"amplitude": "^6.0.0",
|
||||
"apidoc": "^0.54.0",
|
||||
"apple-auth": "^1.0.9",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"bcrypt": "^5.1.1",
|
||||
"body-parser": "^1.20.2",
|
||||
"body-parser": "^1.20.3",
|
||||
"bootstrap": "^4.6.2",
|
||||
"compression": "^1.7.4",
|
||||
"cookie-session": "^2.0.0",
|
||||
@@ -27,7 +28,7 @@
|
||||
"eslint": "^8.55.0",
|
||||
"eslint-config-habitrpg": "^6.2.3",
|
||||
"eslint-plugin-mocha": "^5.0.0",
|
||||
"express": "^4.19.2",
|
||||
"express": "^4.21.1",
|
||||
"express-basic-auth": "^1.2.1",
|
||||
"express-validator": "^5.2.0",
|
||||
"firebase-admin": "^12.1.1",
|
||||
@@ -35,6 +36,7 @@
|
||||
"got": "^11.8.6",
|
||||
"gulp": "^4.0.0",
|
||||
"gulp-babel": "^8.0.0",
|
||||
"gulp-filter": "^7.0.0",
|
||||
"gulp-imagemin": "^7.1.0",
|
||||
"gulp-nodemon": "^2.5.0",
|
||||
"gulp.spritesmith": "^6.13.0",
|
||||
@@ -49,7 +51,7 @@
|
||||
"method-override": "^3.0.0",
|
||||
"moment": "^2.29.4",
|
||||
"moment-recur": "^1.0.7",
|
||||
"mongoose": "^7.6.3",
|
||||
"mongoose": "^7.8.3",
|
||||
"morgan": "^1.10.0",
|
||||
"nconf": "^0.12.1",
|
||||
"node-gcm": "^1.0.5",
|
||||
@@ -74,6 +76,7 @@
|
||||
"useragent": "^2.1.9",
|
||||
"uuid": "^9.0.0",
|
||||
"validator": "^13.11.0",
|
||||
"webpack-bundle-analyzer": "^4.10.2",
|
||||
"winston": "^3.10.0",
|
||||
"winston-loggly-bulk": "^3.3.0",
|
||||
"xml2js": "^0.6.2"
|
||||
@@ -104,19 +107,20 @@
|
||||
"client:build": "cd website/client && npm run build",
|
||||
"client:unit": "cd website/client && npm run test:unit",
|
||||
"start": "gulp nodemon",
|
||||
"start:simple": "node ./website/server/index.js",
|
||||
"debug": "gulp nodemon --inspect",
|
||||
"mongo:dev": "run-rs -v 5.0.23 -l ubuntu1804 --keep --dbpath mongodb-data --number 1 --quiet",
|
||||
"postinstall": "git config --global url.\"https://\".insteadOf git:// && gulp build && cd website/client && npm install",
|
||||
"apidoc": "gulp apidoc",
|
||||
"heroku-postbuild": "npm run client:build"
|
||||
"heroku-postbuild": ".heroku/report_deploy.sh"
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios": "^1.4.0",
|
||||
"axios": "^1.7.4",
|
||||
"chai": "^4.3.7",
|
||||
"chai-as-promised": "^7.1.1",
|
||||
"chai-moment": "^0.1.0",
|
||||
"chalk": "^5.3.0",
|
||||
"cross-spawn": "^7.0.3",
|
||||
"cross-spawn": "^7.0.5",
|
||||
"mocha": "^5.1.1",
|
||||
"monk": "^7.3.4",
|
||||
"nyc": "^15.1.0",
|
||||
|
||||
@@ -44,7 +44,6 @@ describe('bug-report', () => {
|
||||
USER_HOURGLASSES: 0,
|
||||
USER_ID: userId,
|
||||
USER_LEVEL: 1,
|
||||
USER_OFFSET_MONTHS: 0,
|
||||
USER_PAYMENT_PLATFORM: undefined,
|
||||
USER_SUBSCRIPTION: undefined,
|
||||
USER_TIMEZONE_OFFSET: 0,
|
||||
|
||||
@@ -154,6 +154,14 @@ describe('cron', async () => {
|
||||
expect(user.purchased.plan.consecutive.count).to.equal(1);
|
||||
});
|
||||
|
||||
it('increments plan.cumulativeCount', async () => {
|
||||
user.purchased.plan.cumulativeCount = 0;
|
||||
await cron({
|
||||
user, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user.purchased.plan.cumulativeCount).to.equal(1);
|
||||
});
|
||||
|
||||
it('increments plan.consecutive.count by more than 1 if user skipped months between logins', async () => {
|
||||
user.purchased.plan.dateUpdated = moment().subtract(2, 'months').toDate();
|
||||
user.purchased.plan.consecutive.count = 0;
|
||||
@@ -163,12 +171,13 @@ describe('cron', async () => {
|
||||
expect(user.purchased.plan.consecutive.count).to.equal(2);
|
||||
});
|
||||
|
||||
it('decrements plan.consecutive.offset when offset is greater than 0', async () => {
|
||||
user.purchased.plan.consecutive.offset = 2;
|
||||
it('increments plan.cumulativeCount by more than 1 if user skipped months between logins', async () => {
|
||||
user.purchased.plan.dateUpdated = moment().subtract(3, 'months').toDate();
|
||||
user.purchased.plan.cumulativeCount = 0;
|
||||
await cron({
|
||||
user, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user.purchased.plan.consecutive.offset).to.equal(1);
|
||||
expect(user.purchased.plan.cumulativeCount).to.equal(3);
|
||||
});
|
||||
|
||||
it('does not award unearned plan.consecutive.trinkets if subscription ended during an absence', async () => {
|
||||
@@ -185,12 +194,12 @@ describe('cron', async () => {
|
||||
});
|
||||
|
||||
it('does not increment plan.consecutive.gemCapExtra when user has reached the gemCap limit', async () => {
|
||||
user.purchased.plan.consecutive.gemCapExtra = 25;
|
||||
user.purchased.plan.consecutive.gemCapExtra = 26;
|
||||
user.purchased.plan.consecutive.count = 5;
|
||||
await cron({
|
||||
user, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.equal(25);
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.equal(26);
|
||||
});
|
||||
|
||||
it('does not reset plan stats if we are before the last day of the cancelled month', async () => {
|
||||
@@ -205,16 +214,14 @@ describe('cron', async () => {
|
||||
user.purchased.plan.dateTerminated = moment(new Date()).subtract({ days: 1 });
|
||||
user.purchased.plan.consecutive.gemCapExtra = 20;
|
||||
user.purchased.plan.consecutive.count = 5;
|
||||
user.purchased.plan.consecutive.offset = 1;
|
||||
|
||||
await cron({
|
||||
user, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
|
||||
expect(user.purchased.plan.customerId).to.not.exist;
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.equal(0);
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.equal(20);
|
||||
expect(user.purchased.plan.consecutive.count).to.equal(0);
|
||||
expect(user.purchased.plan.consecutive.offset).to.equal(0);
|
||||
});
|
||||
|
||||
describe('for a 1-month recurring subscription', async () => {
|
||||
@@ -236,13 +243,11 @@ describe('cron', async () => {
|
||||
user1.purchased.plan.dateUpdated = moment().toDate();
|
||||
user1.purchased.plan.planId = 'basic';
|
||||
user1.purchased.plan.consecutive.count = 0;
|
||||
user1.purchased.plan.perkMonthCount = 0;
|
||||
user1.purchased.plan.consecutive.offset = 0;
|
||||
user1.purchased.plan.consecutive.trinkets = 0;
|
||||
user1.purchased.plan.consecutive.trinkets = 1;
|
||||
user1.purchased.plan.consecutive.gemCapExtra = 0;
|
||||
});
|
||||
|
||||
it('does not increment consecutive benefits after the first month', async () => {
|
||||
it('increments consecutive benefits', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(1, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
@@ -253,75 +258,8 @@ describe('cron', async () => {
|
||||
user: user1, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user1.purchased.plan.consecutive.count).to.equal(1);
|
||||
expect(user1.purchased.plan.consecutive.offset).to.equal(0);
|
||||
expect(user1.purchased.plan.consecutive.trinkets).to.equal(0);
|
||||
expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(0);
|
||||
});
|
||||
|
||||
it('does not increment consecutive benefits after the second month', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(2, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
// Add 1 month to simulate what happens a month after the subscription was created.
|
||||
// Add 2 days so that we're sure we're not affected by any start-of-month effects
|
||||
// e.g., from time zone oddness.
|
||||
await cron({
|
||||
user: user1, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user1.purchased.plan.consecutive.count).to.equal(2);
|
||||
expect(user1.purchased.plan.consecutive.offset).to.equal(0);
|
||||
expect(user1.purchased.plan.consecutive.trinkets).to.equal(0);
|
||||
expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(0);
|
||||
});
|
||||
|
||||
it('increments consecutive benefits after the second month if they also received a 1 month gift subscription', async () => {
|
||||
user1.purchased.plan.perkMonthCount = 1;
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(2, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
// Add 1 month to simulate what happens a month after the subscription was created.
|
||||
// Add 2 days so that we're sure we're not affected by any start-of-month effects
|
||||
// e.g., from time zone oddness.
|
||||
await cron({
|
||||
user: user1, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user1.purchased.plan.perkMonthCount).to.equal(0);
|
||||
expect(user1.purchased.plan.consecutive.count).to.equal(2);
|
||||
expect(user1.purchased.plan.consecutive.offset).to.equal(0);
|
||||
expect(user1.purchased.plan.consecutive.trinkets).to.equal(1);
|
||||
expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(5);
|
||||
});
|
||||
|
||||
it('increments consecutive benefits after the third month', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(3, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
// Add 1 month to simulate what happens a month after the subscription was created.
|
||||
// Add 2 days so that we're sure we're not affected by any start-of-month effects
|
||||
// e.g., from time zone oddness.
|
||||
await cron({
|
||||
user: user1, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user1.purchased.plan.consecutive.count).to.equal(3);
|
||||
expect(user1.purchased.plan.consecutive.offset).to.equal(0);
|
||||
expect(user1.purchased.plan.consecutive.trinkets).to.equal(1);
|
||||
expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(5);
|
||||
});
|
||||
|
||||
it('does not increment consecutive benefits after the fourth month', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(4, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
// Add 1 month to simulate what happens a month after the subscription was created.
|
||||
// Add 2 days so that we're sure we're not affected by any start-of-month effects
|
||||
// e.g., from time zone oddness.
|
||||
await cron({
|
||||
user: user1, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user1.purchased.plan.consecutive.count).to.equal(4);
|
||||
expect(user1.purchased.plan.consecutive.offset).to.equal(0);
|
||||
expect(user1.purchased.plan.consecutive.trinkets).to.equal(1);
|
||||
expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(5);
|
||||
expect(user1.purchased.plan.consecutive.trinkets).to.equal(2);
|
||||
expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(2);
|
||||
});
|
||||
|
||||
it('increments consecutive benefits correctly if user has been absent with continuous subscription', async () => {
|
||||
@@ -332,33 +270,8 @@ describe('cron', async () => {
|
||||
user: user1, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user1.purchased.plan.consecutive.count).to.equal(10);
|
||||
expect(user1.purchased.plan.consecutive.offset).to.equal(0);
|
||||
expect(user1.purchased.plan.consecutive.trinkets).to.equal(3);
|
||||
expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(15);
|
||||
});
|
||||
|
||||
it('initializes plan.perkMonthCount if necessary', async () => {
|
||||
user.purchased.plan.perkMonthCount = undefined;
|
||||
clock = sinon.useFakeTimers(moment(user.purchased.plan.dateUpdated)
|
||||
.utcOffset(0)
|
||||
.startOf('month')
|
||||
.add(1, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user.purchased.plan.perkMonthCount).to.equal(1);
|
||||
user.purchased.plan.perkMonthCount = undefined;
|
||||
user.purchased.plan.consecutive.count = 8;
|
||||
clock.restore();
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(2, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user.purchased.plan.perkMonthCount).to.equal(2);
|
||||
expect(user1.purchased.plan.consecutive.trinkets).to.equal(11);
|
||||
expect(user1.purchased.plan.consecutive.gemCapExtra).to.equal(20);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -379,14 +292,12 @@ describe('cron', async () => {
|
||||
user3.purchased.plan.customerId = 'subscribedId';
|
||||
user3.purchased.plan.dateUpdated = moment().toDate();
|
||||
user3.purchased.plan.planId = 'basic_3mo';
|
||||
user3.purchased.plan.perkMonthCount = 0;
|
||||
user3.purchased.plan.consecutive.count = 0;
|
||||
user3.purchased.plan.consecutive.offset = 3;
|
||||
user3.purchased.plan.consecutive.trinkets = 1;
|
||||
user3.purchased.plan.consecutive.gemCapExtra = 5;
|
||||
user3.purchased.plan.consecutive.gemCapExtra = 0;
|
||||
});
|
||||
|
||||
it('does not increment consecutive benefits in the first month of the first paid period that they already have benefits for', async () => {
|
||||
it('increments consecutive benefits', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(1, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
@@ -394,102 +305,8 @@ describe('cron', async () => {
|
||||
user: user3, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user3.purchased.plan.consecutive.count).to.equal(1);
|
||||
expect(user3.purchased.plan.consecutive.offset).to.equal(2);
|
||||
expect(user3.purchased.plan.consecutive.trinkets).to.equal(1);
|
||||
expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(5);
|
||||
});
|
||||
|
||||
it('does not increment consecutive benefits in the middle of the period that they already have benefits for', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(2, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user: user3, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user3.purchased.plan.consecutive.count).to.equal(2);
|
||||
expect(user3.purchased.plan.consecutive.offset).to.equal(1);
|
||||
expect(user3.purchased.plan.consecutive.trinkets).to.equal(1);
|
||||
expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(5);
|
||||
});
|
||||
|
||||
it('does not increment consecutive benefits in the final month of the period that they already have benefits for', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(3, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user: user3, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user3.purchased.plan.consecutive.count).to.equal(3);
|
||||
expect(user3.purchased.plan.consecutive.offset).to.equal(0);
|
||||
expect(user3.purchased.plan.consecutive.trinkets).to.equal(1);
|
||||
expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(5);
|
||||
});
|
||||
|
||||
it('increments consecutive benefits the month after the second paid period has started', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(4, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user: user3, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user3.purchased.plan.consecutive.count).to.equal(4);
|
||||
expect(user3.purchased.plan.consecutive.offset).to.equal(2);
|
||||
expect(user3.purchased.plan.consecutive.trinkets).to.equal(2);
|
||||
expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(10);
|
||||
});
|
||||
|
||||
it('keeps existing plan.perkMonthCount intact when incrementing consecutive benefits', async () => {
|
||||
user3.purchased.plan.perkMonthCount = 2;
|
||||
user3.purchased.plan.consecutive.trinkets = 1;
|
||||
user3.purchased.plan.consecutive.gemCapExtra = 5;
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(4, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user: user3, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user3.purchased.plan.perkMonthCount).to.equal(2);
|
||||
expect(user3.purchased.plan.consecutive.trinkets).to.equal(2);
|
||||
expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(10);
|
||||
});
|
||||
|
||||
it('does not increment consecutive benefits in the second month of the second period that they already have benefits for', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(5, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user: user3, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user3.purchased.plan.consecutive.count).to.equal(5);
|
||||
expect(user3.purchased.plan.consecutive.offset).to.equal(1);
|
||||
expect(user3.purchased.plan.consecutive.trinkets).to.equal(2);
|
||||
expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(10);
|
||||
});
|
||||
|
||||
it('does not increment consecutive benefits in the final month of the second period that they already have benefits for', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(6, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user: user3, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user3.purchased.plan.consecutive.count).to.equal(6);
|
||||
expect(user3.purchased.plan.consecutive.offset).to.equal(0);
|
||||
expect(user3.purchased.plan.consecutive.trinkets).to.equal(2);
|
||||
expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(10);
|
||||
});
|
||||
|
||||
it('increments consecutive benefits the month after the third paid period has started', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(7, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user: user3, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user3.purchased.plan.consecutive.count).to.equal(7);
|
||||
expect(user3.purchased.plan.consecutive.offset).to.equal(2);
|
||||
expect(user3.purchased.plan.consecutive.trinkets).to.equal(3);
|
||||
expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(15);
|
||||
expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(2);
|
||||
});
|
||||
|
||||
it('increments consecutive benefits correctly if user has been absent with continuous subscription', async () => {
|
||||
@@ -500,8 +317,7 @@ describe('cron', async () => {
|
||||
user: user3, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user3.purchased.plan.consecutive.count).to.equal(10);
|
||||
expect(user3.purchased.plan.consecutive.offset).to.equal(2);
|
||||
expect(user3.purchased.plan.consecutive.trinkets).to.equal(4);
|
||||
expect(user3.purchased.plan.consecutive.trinkets).to.equal(11);
|
||||
expect(user3.purchased.plan.consecutive.gemCapExtra).to.equal(20);
|
||||
});
|
||||
});
|
||||
@@ -523,14 +339,12 @@ describe('cron', async () => {
|
||||
user6.purchased.plan.customerId = 'subscribedId';
|
||||
user6.purchased.plan.dateUpdated = moment().toDate();
|
||||
user6.purchased.plan.planId = 'google_6mo';
|
||||
user6.purchased.plan.perkMonthCount = 0;
|
||||
user6.purchased.plan.consecutive.count = 0;
|
||||
user6.purchased.plan.consecutive.offset = 6;
|
||||
user6.purchased.plan.consecutive.trinkets = 2;
|
||||
user6.purchased.plan.consecutive.gemCapExtra = 10;
|
||||
user6.purchased.plan.consecutive.trinkets = 1;
|
||||
user6.purchased.plan.consecutive.gemCapExtra = 0;
|
||||
});
|
||||
|
||||
it('does not increment consecutive benefits in the first month of the first paid period that they already have benefits for', async () => {
|
||||
it('increments benefits', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(1, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
@@ -538,74 +352,8 @@ describe('cron', async () => {
|
||||
user: user6, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user6.purchased.plan.consecutive.count).to.equal(1);
|
||||
expect(user6.purchased.plan.consecutive.offset).to.equal(5);
|
||||
expect(user6.purchased.plan.consecutive.trinkets).to.equal(2);
|
||||
expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(10);
|
||||
});
|
||||
|
||||
it('does not increment consecutive benefits in the final month of the period that they already have benefits for', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(6, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user: user6, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user6.purchased.plan.consecutive.count).to.equal(6);
|
||||
expect(user6.purchased.plan.consecutive.offset).to.equal(0);
|
||||
expect(user6.purchased.plan.consecutive.trinkets).to.equal(2);
|
||||
expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(10);
|
||||
});
|
||||
|
||||
it('increments consecutive benefits the month after the second paid period has started', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(7, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user: user6, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user6.purchased.plan.consecutive.count).to.equal(7);
|
||||
expect(user6.purchased.plan.consecutive.offset).to.equal(5);
|
||||
expect(user6.purchased.plan.consecutive.trinkets).to.equal(4);
|
||||
expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(20);
|
||||
});
|
||||
|
||||
it('keeps existing plan.perkMonthCount intact when incrementing consecutive benefits', async () => {
|
||||
user6.purchased.plan.perkMonthCount = 2;
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(7, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user: user6, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user6.purchased.plan.perkMonthCount).to.equal(2);
|
||||
expect(user6.purchased.plan.consecutive.trinkets).to.equal(4);
|
||||
expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(20);
|
||||
});
|
||||
|
||||
it('increments consecutive benefits the month after the third paid period has started', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(13, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user: user6, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user6.purchased.plan.consecutive.count).to.equal(13);
|
||||
expect(user6.purchased.plan.consecutive.offset).to.equal(5);
|
||||
expect(user6.purchased.plan.consecutive.trinkets).to.equal(6);
|
||||
expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(25);
|
||||
});
|
||||
|
||||
it('increments consecutive benefits correctly if user has been absent with continuous subscription', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(19, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user: user6, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user6.purchased.plan.consecutive.count).to.equal(19);
|
||||
expect(user6.purchased.plan.consecutive.offset).to.equal(5);
|
||||
expect(user6.purchased.plan.consecutive.trinkets).to.equal(8);
|
||||
expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(25);
|
||||
expect(user6.purchased.plan.consecutive.gemCapExtra).to.equal(2);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -626,11 +374,10 @@ describe('cron', async () => {
|
||||
user12.purchased.plan.dateUpdated = moment().toDate();
|
||||
user12.purchased.plan.planId = 'basic_12mo';
|
||||
user12.purchased.plan.consecutive.count = 0;
|
||||
user12.purchased.plan.consecutive.offset = 12;
|
||||
user12.purchased.plan.consecutive.trinkets = 4;
|
||||
user12.purchased.plan.consecutive.gemCapExtra = 20;
|
||||
user12.purchased.plan.consecutive.trinkets = 1;
|
||||
user12.purchased.plan.consecutive.gemCapExtra = 26;
|
||||
|
||||
it('does not increment consecutive benefits in the first month of the first paid period that they already have benefits for', async () => {
|
||||
it('increments consecutive benefits the month after the second paid period has started', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(1, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
@@ -638,61 +385,20 @@ describe('cron', async () => {
|
||||
user: user12, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user12.purchased.plan.consecutive.count).to.equal(1);
|
||||
expect(user12.purchased.plan.consecutive.offset).to.equal(11);
|
||||
expect(user12.purchased.plan.consecutive.trinkets).to.equal(4);
|
||||
expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(20);
|
||||
});
|
||||
|
||||
it('does not increment consecutive benefits in the final month of the period that they already have benefits for', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(12, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user: user12, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user12.purchased.plan.consecutive.count).to.equal(12);
|
||||
expect(user12.purchased.plan.consecutive.offset).to.equal(0);
|
||||
expect(user12.purchased.plan.consecutive.trinkets).to.equal(4);
|
||||
expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(20);
|
||||
});
|
||||
|
||||
it('increments consecutive benefits the month after the second paid period has started', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(13, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user: user12, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user12.purchased.plan.consecutive.count).to.equal(13);
|
||||
expect(user12.purchased.plan.consecutive.offset).to.equal(11);
|
||||
expect(user12.purchased.plan.consecutive.trinkets).to.equal(8);
|
||||
expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(25);
|
||||
});
|
||||
|
||||
it('increments consecutive benefits the month after the third paid period has started', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(25, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user: user12, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user12.purchased.plan.consecutive.count).to.equal(25);
|
||||
expect(user12.purchased.plan.consecutive.offset).to.equal(11);
|
||||
expect(user12.purchased.plan.consecutive.trinkets).to.equal(12);
|
||||
expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(25);
|
||||
expect(user12.purchased.plan.consecutive.trinkets).to.equal(2);
|
||||
expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(26);
|
||||
});
|
||||
|
||||
it('increments consecutive benefits correctly if user has been absent with continuous subscription', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(37, 'months')
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(10, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user: user12, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user12.purchased.plan.consecutive.count).to.equal(37);
|
||||
expect(user12.purchased.plan.consecutive.offset).to.equal(11);
|
||||
expect(user12.purchased.plan.consecutive.trinkets).to.equal(16);
|
||||
expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(25);
|
||||
expect(user12.purchased.plan.consecutive.count).to.equal(10);
|
||||
expect(user12.purchased.plan.consecutive.trinkets).to.equal(11);
|
||||
expect(user12.purchased.plan.consecutive.gemCapExtra).to.equal(26);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -715,11 +421,11 @@ describe('cron', async () => {
|
||||
.toDate();
|
||||
user3g.purchased.plan.planId = null;
|
||||
user3g.purchased.plan.consecutive.count = 0;
|
||||
user3g.purchased.plan.consecutive.offset = 3;
|
||||
user3g.purchased.plan.cumulativeCount = 0;
|
||||
user3g.purchased.plan.consecutive.trinkets = 1;
|
||||
user3g.purchased.plan.consecutive.gemCapExtra = 5;
|
||||
user3g.purchased.plan.consecutive.gemCapExtra = 0;
|
||||
|
||||
it('does not increment consecutive benefits in the first month of the gift subscription', async () => {
|
||||
it('increments benefits', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(1, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
@@ -727,35 +433,9 @@ describe('cron', async () => {
|
||||
user: user3g, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user3g.purchased.plan.consecutive.count).to.equal(1);
|
||||
expect(user3g.purchased.plan.consecutive.offset).to.equal(2);
|
||||
expect(user3g.purchased.plan.consecutive.trinkets).to.equal(1);
|
||||
expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(5);
|
||||
});
|
||||
|
||||
it('does not increment consecutive benefits in the second month of the gift subscription', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(2, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user: user3g, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user3g.purchased.plan.consecutive.count).to.equal(2);
|
||||
expect(user3g.purchased.plan.consecutive.offset).to.equal(1);
|
||||
expect(user3g.purchased.plan.consecutive.trinkets).to.equal(1);
|
||||
expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(5);
|
||||
});
|
||||
|
||||
it('does not increment consecutive benefits in the third month of the gift subscription', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(3, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user: user3g, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user3g.purchased.plan.consecutive.count).to.equal(3);
|
||||
expect(user3g.purchased.plan.consecutive.offset).to.equal(0);
|
||||
expect(user3g.purchased.plan.consecutive.trinkets).to.equal(1);
|
||||
expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(5);
|
||||
expect(user3g.purchased.plan.cumulativeCount).to.equal(1);
|
||||
expect(user3g.purchased.plan.consecutive.trinkets).to.equal(2);
|
||||
expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(2);
|
||||
});
|
||||
|
||||
it('does not increment consecutive benefits in the month after the gift subscription has ended', async () => {
|
||||
@@ -767,84 +447,9 @@ describe('cron', async () => {
|
||||
});
|
||||
// subscription has been erased by now
|
||||
expect(user3g.purchased.plan.consecutive.count).to.equal(0);
|
||||
expect(user3g.purchased.plan.consecutive.offset).to.equal(0);
|
||||
expect(user3g.purchased.plan.consecutive.trinkets).to.equal(1);
|
||||
expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(0); // erased
|
||||
});
|
||||
});
|
||||
|
||||
describe('for a 6-month recurring subscription where the user has incorrect consecutive month data from prior bugs', async () => {
|
||||
const user6x = new User({
|
||||
auth: {
|
||||
local: {
|
||||
username: 'username6x',
|
||||
lowerCaseUsername: 'username6x',
|
||||
email: 'email6x@example.com',
|
||||
salt: 'salt',
|
||||
hashed_password: 'hashed_password', // eslint-disable-line camelcase
|
||||
},
|
||||
},
|
||||
});
|
||||
// user6x has a 6-month recurring subscription starting 8 months in the past
|
||||
// before issue #4819 was fixed
|
||||
user6x.purchased.plan.customerId = 'subscribedId';
|
||||
user6x.purchased.plan.dateUpdated = moment().toDate();
|
||||
user6x.purchased.plan.planId = 'basic_6mo';
|
||||
user6x.purchased.plan.consecutive.count = 8;
|
||||
user6x.purchased.plan.consecutive.offset = 0;
|
||||
user6x.purchased.plan.consecutive.trinkets = 3;
|
||||
user6x.purchased.plan.consecutive.gemCapExtra = 15;
|
||||
|
||||
it('increments consecutive benefits in the first month since the fix for #4819 goes live', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(1, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user: user6x, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user6x.purchased.plan.consecutive.count).to.equal(9);
|
||||
expect(user6x.purchased.plan.consecutive.offset).to.equal(5);
|
||||
expect(user6x.purchased.plan.consecutive.trinkets).to.equal(5);
|
||||
expect(user6x.purchased.plan.consecutive.gemCapExtra).to.equal(25);
|
||||
});
|
||||
|
||||
it('does not increment consecutive benefits in the second month after the fix goes live', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(2, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user: user6x, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user6x.purchased.plan.consecutive.count).to.equal(10);
|
||||
expect(user6x.purchased.plan.consecutive.offset).to.equal(4);
|
||||
expect(user6x.purchased.plan.consecutive.trinkets).to.equal(5);
|
||||
expect(user6x.purchased.plan.consecutive.gemCapExtra).to.equal(25);
|
||||
});
|
||||
|
||||
it('does not increment consecutive benefits in the third month after the fix goes live', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(3, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user: user6x, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user6x.purchased.plan.consecutive.count).to.equal(11);
|
||||
expect(user6x.purchased.plan.consecutive.offset).to.equal(3);
|
||||
expect(user6x.purchased.plan.consecutive.trinkets).to.equal(5);
|
||||
expect(user6x.purchased.plan.consecutive.gemCapExtra).to.equal(25);
|
||||
});
|
||||
|
||||
it('increments consecutive benefits in the seventh month after the fix goes live', async () => {
|
||||
clock = sinon.useFakeTimers(moment().utcOffset(0).startOf('month').add(7, 'months')
|
||||
.add(2, 'days')
|
||||
.toDate());
|
||||
await cron({
|
||||
user: user6x, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user6x.purchased.plan.consecutive.count).to.equal(15);
|
||||
expect(user6x.purchased.plan.consecutive.offset).to.equal(5);
|
||||
expect(user6x.purchased.plan.consecutive.trinkets).to.equal(7);
|
||||
expect(user6x.purchased.plan.consecutive.gemCapExtra).to.equal(25);
|
||||
expect(user3g.purchased.plan.consecutive.trinkets).to.equal(2);
|
||||
expect(user3g.purchased.plan.consecutive.gemCapExtra).to.equal(2);
|
||||
expect(user3g.purchased.plan.cumulativeCount).to.equal(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -888,12 +493,12 @@ describe('cron', async () => {
|
||||
expect(user.purchased.plan.consecutive.count).to.equal(0);
|
||||
});
|
||||
|
||||
it('does not decrement plan.consecutive.offset when offset is greater than 0', async () => {
|
||||
user.purchased.plan.consecutive.offset = 1;
|
||||
it('does not increment plan.cumulativeCount', async () => {
|
||||
user.purchased.plan.cumulativeCount = 0;
|
||||
await cron({
|
||||
user, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user.purchased.plan.consecutive.offset).to.equal(1);
|
||||
expect(user.purchased.plan.cumulativeCount).to.equal(0);
|
||||
});
|
||||
|
||||
it('does not increment plan.consecutive.trinkets when user has reached a month that is a multiple of 3', async () => {
|
||||
@@ -913,12 +518,12 @@ describe('cron', async () => {
|
||||
});
|
||||
|
||||
it('does not increment plan.consecutive.gemCapExtra when user has reached the gemCap limit', async () => {
|
||||
user.purchased.plan.consecutive.gemCapExtra = 25;
|
||||
user.purchased.plan.consecutive.gemCapExtra = 26;
|
||||
user.purchased.plan.consecutive.count = 5;
|
||||
await cron({
|
||||
user, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.equal(25);
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.equal(26);
|
||||
});
|
||||
|
||||
it('does nothing to plan stats if we are before the last day of the cancelled month', async () => {
|
||||
@@ -928,22 +533,6 @@ describe('cron', async () => {
|
||||
});
|
||||
expect(user.purchased.plan.customerId).to.not.exist;
|
||||
});
|
||||
|
||||
xit('does nothing to plan stats when we are after the last day of the cancelled month', async () => {
|
||||
user.purchased.plan.dateTerminated = moment(new Date()).subtract({ days: 1 });
|
||||
user.purchased.plan.consecutive.gemCapExtra = 20;
|
||||
user.purchased.plan.consecutive.count = 5;
|
||||
user.purchased.plan.consecutive.offset = 1;
|
||||
|
||||
await cron({
|
||||
user, tasksByType, daysMissed, analytics,
|
||||
});
|
||||
|
||||
expect(user.purchased.plan.customerId).to.exist;
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.exist;
|
||||
expect(user.purchased.plan.consecutive.count).to.exist;
|
||||
expect(user.purchased.plan.consecutive.offset).to.exist;
|
||||
});
|
||||
});
|
||||
|
||||
describe('todos', async () => {
|
||||
|
||||
@@ -715,7 +715,7 @@ describe('Purchasing a group plan for group', () => {
|
||||
const mysteryItem = { title: 'item' };
|
||||
const mysteryItems = [mysteryItem];
|
||||
const consecutive = {
|
||||
trinkets: 3,
|
||||
trinkets: 4,
|
||||
gemCapExtra: 20,
|
||||
offset: 1,
|
||||
count: 13,
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
} from '../../../../helpers/api-unit.helper';
|
||||
import * as worldState from '../../../../../website/server/libs/worldState';
|
||||
import { TransactionModel } from '../../../../../website/server/models/transaction';
|
||||
import { REPEATING_EVENTS } from '../../../../../website/common/script/content/constants/events';
|
||||
|
||||
describe('payments/index', () => {
|
||||
let user;
|
||||
@@ -65,7 +66,6 @@ describe('payments/index', () => {
|
||||
mysteryItems: [],
|
||||
consecutive: {
|
||||
trinkets: 0,
|
||||
offset: 0,
|
||||
gemCapExtra: 0,
|
||||
},
|
||||
};
|
||||
@@ -108,14 +108,8 @@ describe('payments/index', () => {
|
||||
});
|
||||
|
||||
it('add a transaction entry to the recipient', async () => {
|
||||
recipient.purchased.plan = plan;
|
||||
|
||||
expect(recipient.purchased.plan.extraMonths).to.eql(0);
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(recipient.purchased.plan.extraMonths).to.eql(3);
|
||||
|
||||
const transactions = await TransactionModel
|
||||
.find({ userId: recipient._id })
|
||||
.sort({ createdAt: -1 })
|
||||
@@ -177,6 +171,45 @@ describe('payments/index', () => {
|
||||
expect(recipient.purchased.plan.dateUpdated).to.exist;
|
||||
});
|
||||
|
||||
it('does not reset gemCapExtra if they already had one', async () => {
|
||||
recipient.purchased.plan.consecutive.gemCapExtra = 10;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(recipient.purchased.plan.consecutive.gemCapExtra).to.eql(10);
|
||||
});
|
||||
|
||||
it('sets gemCapExtra to 0 if they receive a 3 month sub', async () => {
|
||||
data.gift.subscription.key = 'basic_3mo';
|
||||
data.gift.subscription.months = 3;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(recipient.purchased.plan.consecutive.gemCapExtra).to.eql(0);
|
||||
});
|
||||
|
||||
it('sets gemCapExtra to max if they receive a 12 month sub', async () => {
|
||||
recipient.purchased.plan.consecutive.gemCapExtra = 10;
|
||||
|
||||
data.gift.subscription.key = 'basic_12mo';
|
||||
data.gift.subscription.months = 12;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(recipient.purchased.plan.consecutive.gemCapExtra).to.eql(26);
|
||||
});
|
||||
|
||||
it('gives user 1 hourglass if they have no active subscription', async () => {
|
||||
await api.createSubscription(data);
|
||||
expect(recipient.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
});
|
||||
|
||||
it('does not give any hourglasses if they have an active subscription', async () => {
|
||||
recipient.purchased.plan = plan;
|
||||
await api.createSubscription(data);
|
||||
expect(recipient.purchased.plan.consecutive.trinkets).to.eql(plan.consecutive.trinkets);
|
||||
});
|
||||
|
||||
it('sets plan.dateUpdated if it did exist but the user has cancelled', async () => {
|
||||
recipient.purchased.plan.dateUpdated = moment().subtract(1, 'days').toDate();
|
||||
recipient.purchased.plan.dateTerminated = moment().subtract(1, 'days').toDate();
|
||||
@@ -235,116 +268,6 @@ describe('payments/index', () => {
|
||||
expect(recipient.purchased.plan.customerId).to.eql('customer-id');
|
||||
});
|
||||
|
||||
it('sets plan.perkMonthCount to 1 if user is not subscribed', async () => {
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.purchased.plan.perkMonthCount = 1;
|
||||
recipient.purchased.plan.customerId = undefined;
|
||||
data.sub.key = 'basic_earned';
|
||||
data.gift.subscription.key = 'basic_earned';
|
||||
data.gift.subscription.months = 1;
|
||||
|
||||
expect(recipient.purchased.plan.perkMonthCount).to.eql(1);
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(recipient.purchased.plan.perkMonthCount).to.eql(1);
|
||||
});
|
||||
|
||||
it('sets plan.perkMonthCount to 1 if field is not initialized', async () => {
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.purchased.plan.perkMonthCount = -1;
|
||||
recipient.purchased.plan.customerId = undefined;
|
||||
data.sub.key = 'basic_earned';
|
||||
data.gift.subscription.key = 'basic_earned';
|
||||
data.gift.subscription.months = 1;
|
||||
|
||||
expect(recipient.purchased.plan.perkMonthCount).to.eql(-1);
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(recipient.purchased.plan.perkMonthCount).to.eql(1);
|
||||
});
|
||||
|
||||
it('sets plan.perkMonthCount to 1 if user had previous count but lapsed subscription', async () => {
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.purchased.plan.perkMonthCount = 2;
|
||||
recipient.purchased.plan.customerId = undefined;
|
||||
data.sub.key = 'basic_earned';
|
||||
data.gift.subscription.key = 'basic_earned';
|
||||
data.gift.subscription.months = 1;
|
||||
|
||||
expect(recipient.purchased.plan.perkMonthCount).to.eql(2);
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(recipient.purchased.plan.perkMonthCount).to.eql(1);
|
||||
});
|
||||
|
||||
it('adds to plan.perkMonthCount if user is already subscribed', async () => {
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.purchased.plan.perkMonthCount = 1;
|
||||
data.sub.key = 'basic_earned';
|
||||
data.gift.subscription.key = 'basic_earned';
|
||||
data.gift.subscription.months = 1;
|
||||
|
||||
expect(recipient.purchased.plan.perkMonthCount).to.eql(1);
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(recipient.purchased.plan.perkMonthCount).to.eql(2);
|
||||
});
|
||||
|
||||
it('awards perks if plan.perkMonthCount reaches 3 with existing subscription', async () => {
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.purchased.plan.perkMonthCount = 2;
|
||||
data.sub.key = 'basic_earned';
|
||||
data.gift.subscription.key = 'basic_earned';
|
||||
data.gift.subscription.months = 1;
|
||||
|
||||
expect(recipient.purchased.plan.perkMonthCount).to.eql(2);
|
||||
expect(recipient.purchased.plan.consecutive.trinkets).to.eql(0);
|
||||
expect(recipient.purchased.plan.consecutive.gemCapExtra).to.eql(0);
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(recipient.purchased.plan.perkMonthCount).to.eql(0);
|
||||
expect(recipient.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
expect(recipient.purchased.plan.consecutive.gemCapExtra).to.eql(5);
|
||||
});
|
||||
|
||||
it('awards perks if plan.perkMonthCount reaches 3 without existing subscription', async () => {
|
||||
recipient.purchased.plan.perkMonthCount = 0;
|
||||
expect(recipient.purchased.plan.perkMonthCount).to.eql(0);
|
||||
expect(recipient.purchased.plan.consecutive.trinkets).to.eql(0);
|
||||
expect(recipient.purchased.plan.consecutive.gemCapExtra).to.eql(0);
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(recipient.purchased.plan.perkMonthCount).to.eql(0);
|
||||
expect(recipient.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
expect(recipient.purchased.plan.consecutive.gemCapExtra).to.eql(5);
|
||||
});
|
||||
|
||||
it('awards perks if plan.perkMonthCount reaches 3 without initialized field', async () => {
|
||||
expect(recipient.purchased.plan.perkMonthCount).to.eql(-1);
|
||||
expect(recipient.purchased.plan.consecutive.trinkets).to.eql(0);
|
||||
expect(recipient.purchased.plan.consecutive.gemCapExtra).to.eql(0);
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(recipient.purchased.plan.perkMonthCount).to.eql(0);
|
||||
expect(recipient.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
expect(recipient.purchased.plan.consecutive.gemCapExtra).to.eql(5);
|
||||
});
|
||||
|
||||
it('awards perks if plan.perkMonthCount goes over 3', async () => {
|
||||
recipient.purchased.plan = plan;
|
||||
recipient.purchased.plan.perkMonthCount = 2;
|
||||
data.sub.key = 'basic_earned';
|
||||
|
||||
expect(recipient.purchased.plan.perkMonthCount).to.eql(2);
|
||||
expect(recipient.purchased.plan.consecutive.trinkets).to.eql(0);
|
||||
expect(recipient.purchased.plan.consecutive.gemCapExtra).to.eql(0);
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(recipient.purchased.plan.perkMonthCount).to.eql(2);
|
||||
expect(recipient.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
expect(recipient.purchased.plan.consecutive.gemCapExtra).to.eql(5);
|
||||
});
|
||||
|
||||
it('sets plan.customerId to "Gift" if it does not already exist', async () => {
|
||||
expect(recipient.purchased.plan.customerId).to.not.exist;
|
||||
|
||||
@@ -421,8 +344,8 @@ describe('payments/index', () => {
|
||||
context('Active Promotion', () => {
|
||||
beforeEach(() => {
|
||||
sinon.stub(worldState, 'getCurrentEventList').returns([{
|
||||
...common.content.events.winter2021Promo,
|
||||
event: 'winter2021',
|
||||
...REPEATING_EVENTS.giftOneGetOne,
|
||||
event: 'g1g1',
|
||||
}]);
|
||||
});
|
||||
|
||||
@@ -438,22 +361,30 @@ describe('payments/index', () => {
|
||||
expect(user.purchased.plan.dateTerminated).to.exist;
|
||||
expect(user.purchased.plan.dateUpdated).to.exist;
|
||||
expect(user.purchased.plan.dateCreated).to.exist;
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(0);
|
||||
|
||||
expect(recipient.items.pets['Jackalope-RoyalPurple']).to.eql(5);
|
||||
expect(recipient.purchased.plan.customerId).to.eql('Gift');
|
||||
expect(recipient.purchased.plan.dateTerminated).to.exist;
|
||||
expect(recipient.purchased.plan.dateUpdated).to.exist;
|
||||
expect(recipient.purchased.plan.dateCreated).to.exist;
|
||||
expect(recipient.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
expect(recipient.purchased.plan.consecutive.gemCapExtra).to.eql(0);
|
||||
});
|
||||
|
||||
it('adds extraMonths to existing subscription for purchaser and creates a gift subscription for recipient without sub', async () => {
|
||||
user.purchased.plan = plan;
|
||||
|
||||
expect(user.purchased.plan.extraMonths).to.eql(0);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(0);
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(0);
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.extraMonths).to.eql(3);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(0);
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(0);
|
||||
|
||||
expect(recipient.items.pets['Jackalope-RoyalPurple']).to.eql(5);
|
||||
expect(recipient.purchased.plan.customerId).to.eql('Gift');
|
||||
@@ -466,10 +397,12 @@ describe('payments/index', () => {
|
||||
recipient.purchased.plan = plan;
|
||||
|
||||
expect(recipient.purchased.plan.extraMonths).to.eql(0);
|
||||
expect(recipient.purchased.plan.consecutive.trinkets).to.eql(0);
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(recipient.purchased.plan.extraMonths).to.eql(3);
|
||||
expect(recipient.purchased.plan.consecutive.trinkets).to.eql(0);
|
||||
|
||||
expect(user.items.pets['Jackalope-RoyalPurple']).to.eql(5);
|
||||
expect(user.purchased.plan.customerId).to.eql('Gift');
|
||||
@@ -484,11 +417,15 @@ describe('payments/index', () => {
|
||||
|
||||
expect(user.purchased.plan.extraMonths).to.eql(0);
|
||||
expect(recipient.purchased.plan.extraMonths).to.eql(0);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(0);
|
||||
expect(recipient.purchased.plan.consecutive.trinkets).to.eql(0);
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.extraMonths).to.eql(3);
|
||||
expect(recipient.purchased.plan.extraMonths).to.eql(3);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(0);
|
||||
expect(recipient.purchased.plan.consecutive.trinkets).to.eql(0);
|
||||
});
|
||||
|
||||
it('sends a private message about the promotion', async () => {
|
||||
@@ -511,7 +448,6 @@ describe('payments/index', () => {
|
||||
expect(user.purchased.plan.customerId).to.eql('customer-id');
|
||||
expect(user.purchased.plan.dateUpdated).to.exist;
|
||||
expect(user.purchased.plan.gemsBought).to.eql(0);
|
||||
expect(user.purchased.plan.perkMonthCount).to.eql(0);
|
||||
expect(user.purchased.plan.paymentMethod).to.eql('Payment Method');
|
||||
expect(user.purchased.plan.extraMonths).to.eql(0);
|
||||
expect(user.purchased.plan.dateTerminated).to.eql(null);
|
||||
@@ -549,33 +485,6 @@ describe('payments/index', () => {
|
||||
expect(user.purchased.plan.dateCurrentTypeCreated).to.not.eql(initialDate);
|
||||
});
|
||||
|
||||
it('keeps plan.perkMonthCount when changing subscription type', async () => {
|
||||
await api.createSubscription(data);
|
||||
user.purchased.plan.perkMonthCount = 2;
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.perkMonthCount).to.eql(2);
|
||||
});
|
||||
|
||||
it('sets plan.perkMonthCount to zero when creating new monthly subscription', async () => {
|
||||
user.purchased.plan.perkMonthCount = 2;
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.perkMonthCount).to.eql(0);
|
||||
});
|
||||
|
||||
it('sets plan.perkMonthCount to zero when creating new 3 month subscription', async () => {
|
||||
user.purchased.plan.perkMonthCount = 2;
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.perkMonthCount).to.eql(0);
|
||||
});
|
||||
|
||||
it('updates plan.consecutive.offset when changing subscription type', async () => {
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.consecutive.offset).to.eql(3);
|
||||
data.sub.key = 'basic_6mo';
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.consecutive.offset).to.eql(6);
|
||||
});
|
||||
|
||||
it('awards the Royal Purple Jackalope pet', async () => {
|
||||
await api.createSubscription(data);
|
||||
|
||||
@@ -694,6 +603,7 @@ describe('payments/index', () => {
|
||||
expect(user.purchased.plan.dateCreated).to.eql(created);
|
||||
expect(user.purchased.plan.dateUpdated).to.not.eql(updated);
|
||||
expect(user.purchased.plan.customerId).to.eql('customer-id');
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(26);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -741,55 +651,20 @@ describe('payments/index', () => {
|
||||
});
|
||||
|
||||
context('Block subscription perks', () => {
|
||||
it('adds block months to plan.consecutive.offset', async () => {
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.consecutive.offset).to.eql(3);
|
||||
});
|
||||
|
||||
it('does not add to plans.consecutive.offset if 1 month subscription', async () => {
|
||||
data.sub.key = 'basic_earned';
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.consecutive.offset).to.eql(0);
|
||||
});
|
||||
|
||||
it('resets plans.consecutive.offset if 1 month subscription', async () => {
|
||||
user.purchased.plan.consecutive.offset = 1;
|
||||
await user.save();
|
||||
data.sub.key = 'basic_earned';
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.consecutive.offset).to.eql(0);
|
||||
});
|
||||
|
||||
it('adds 5 to plan.consecutive.gemCapExtra for 3 month block', async () => {
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(5);
|
||||
});
|
||||
|
||||
it('adds 10 to plan.consecutive.gemCapExtra for 6 month block', async () => {
|
||||
data.sub.key = 'basic_6mo';
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(10);
|
||||
});
|
||||
|
||||
it('adds 20 to plan.consecutive.gemCapExtra for 12 month block', async () => {
|
||||
it('adds 26 to plan.consecutive.gemCapExtra for 12 month block', async () => {
|
||||
data.sub.key = 'basic_12mo';
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(20);
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(26);
|
||||
});
|
||||
|
||||
it('does not raise plan.consecutive.gemCapExtra higher than 25', async () => {
|
||||
it('does not raise plan.consecutive.gemCapExtra higher than 26', async () => {
|
||||
data.sub.key = 'basic_12mo';
|
||||
|
||||
await api.createSubscription(data);
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(25);
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(26);
|
||||
});
|
||||
|
||||
it('adds a plan.consecutive.trinkets for 3 month block', async () => {
|
||||
@@ -798,20 +673,29 @@ describe('payments/index', () => {
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
});
|
||||
|
||||
it('adds 2 plan.consecutive.trinkets for 6 month block', async () => {
|
||||
it('adds 1 plan.consecutive.trinkets for 6 month block', async () => {
|
||||
data.sub.key = 'basic_6mo';
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(2);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
});
|
||||
|
||||
it('adds 4 plan.consecutive.trinkets for 12 month block', async () => {
|
||||
it('adds 1 plan.consecutive.trinkets for 12 month block if they had promo', async () => {
|
||||
user.purchased.plan.hourglassPromoReceived = new Date();
|
||||
data.sub.key = 'basic_12mo';
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(4);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
});
|
||||
|
||||
it('adds 12 plan.consecutive.trinkets for 12 month block', async () => {
|
||||
data.sub.key = 'basic_12mo';
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(13);
|
||||
});
|
||||
|
||||
context('Upgrades subscription', () => {
|
||||
@@ -819,70 +703,38 @@ describe('payments/index', () => {
|
||||
beforeEach(async () => {
|
||||
data.updatedFrom = { logic: 'payDifference' };
|
||||
});
|
||||
it('Adds 10 to plan.consecutive.gemCapExtra from basic_earned to basic_6mo', async () => {
|
||||
data.sub.key = 'basic_earned';
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_earned');
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(0);
|
||||
|
||||
data.sub.key = 'basic_6mo';
|
||||
data.updatedFrom.key = 'basic_earned';
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_6mo');
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(10);
|
||||
});
|
||||
|
||||
it('Adds 15 to plan.consecutive.gemCapExtra when upgrading from basic_3mo to basic_12mo', async () => {
|
||||
it('Adds 26 to plan.consecutive.gemCapExtra when upgrading from basic_3mo to basic_12mo', async () => {
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_3mo');
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(5);
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(0);
|
||||
|
||||
data.sub.key = 'basic_12mo';
|
||||
data.updatedFrom.key = 'basic_3mo';
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_12mo');
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(20);
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(26);
|
||||
});
|
||||
|
||||
it('Adds 2 to plan.consecutive.trinkets from basic_earned to basic_6mo', async () => {
|
||||
data.sub.key = 'basic_earned';
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_earned');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(0);
|
||||
|
||||
data.sub.key = 'basic_6mo';
|
||||
data.updatedFrom.key = 'basic_earned';
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_6mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(2);
|
||||
});
|
||||
|
||||
it('Adds 2 to plan.consecutive.trinkets when upgrading from basic_6mo to basic_12mo', async () => {
|
||||
it('Adds 12 to plan.consecutive.trinkets when upgrading from basic_6mo to basic_12mo', async () => {
|
||||
data.sub.key = 'basic_6mo';
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_6mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(2);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
|
||||
data.sub.key = 'basic_12mo';
|
||||
data.updatedFrom.key = 'basic_6mo';
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_12mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(4);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(13);
|
||||
});
|
||||
|
||||
it('Adds 3 to plan.consecutive.trinkets when upgrading from basic_3mo to basic_12mo', async () => {
|
||||
it('Adds 12 to plan.consecutive.trinkets when upgrading from basic_3mo to basic_12mo', async () => {
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
@@ -894,7 +746,7 @@ describe('payments/index', () => {
|
||||
data.updatedFrom.key = 'basic_3mo';
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_12mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(4);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(13);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -902,70 +754,39 @@ describe('payments/index', () => {
|
||||
beforeEach(async () => {
|
||||
data.updatedFrom = { logic: 'payFull' };
|
||||
});
|
||||
it('Adds 10 to plan.consecutive.gemCapExtra from basic_earned to basic_6mo', async () => {
|
||||
data.sub.key = 'basic_earned';
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_earned');
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(0);
|
||||
|
||||
data.sub.key = 'basic_6mo';
|
||||
data.updatedFrom.key = 'basic_earned';
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_6mo');
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(10);
|
||||
});
|
||||
|
||||
it('Adds 20 to plan.consecutive.gemCapExtra when upgrading from basic_3mo to basic_12mo', async () => {
|
||||
it('Adds 26 to plan.consecutive.gemCapExtra when upgrading from basic_3mo to basic_12mo', async () => {
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_3mo');
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(5);
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(0);
|
||||
|
||||
data.sub.key = 'basic_12mo';
|
||||
data.updatedFrom.key = 'basic_3mo';
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_12mo');
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(25);
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(26);
|
||||
});
|
||||
|
||||
it('Adds 2 to plan.consecutive.trinkets from basic_earned to basic_6mo', async () => {
|
||||
data.sub.key = 'basic_earned';
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_earned');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(0);
|
||||
|
||||
data.sub.key = 'basic_6mo';
|
||||
data.updatedFrom.key = 'basic_earned';
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_6mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(2);
|
||||
});
|
||||
|
||||
it('Adds 4 to plan.consecutive.trinkets when upgrading from basic_6mo to basic_12mo', async () => {
|
||||
it('Adds 12 to plan.consecutive.trinkets when upgrading from basic_6mo to basic_12mo', async () => {
|
||||
data.sub.key = 'basic_6mo';
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_6mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(2);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
|
||||
data.sub.key = 'basic_12mo';
|
||||
data.updatedFrom.key = 'basic_6mo';
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_12mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(6);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(13);
|
||||
});
|
||||
|
||||
it('Adds 4 to plan.consecutive.trinkets when upgrading from basic_3mo to basic_12mo', async () => {
|
||||
it('Adds 12 to plan.consecutive.trinkets when upgrading from basic_3mo to basic_12mo', async () => {
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
@@ -977,7 +798,7 @@ describe('payments/index', () => {
|
||||
data.updatedFrom.key = 'basic_3mo';
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_12mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(5);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(13);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -988,30 +809,13 @@ describe('payments/index', () => {
|
||||
data.updatedFrom = { logic: 'refundAndRepay' };
|
||||
});
|
||||
context('Upgrades within first half of subscription', () => {
|
||||
it('Adds 10 to plan.consecutive.gemCapExtra from basic_earned to basic_6mo', async () => {
|
||||
data.sub.key = 'basic_earned';
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_earned');
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(0);
|
||||
|
||||
data.sub.key = 'basic_6mo';
|
||||
data.updatedFrom.key = 'basic_earned';
|
||||
clock.restore();
|
||||
clock = sinon.useFakeTimers(new Date('2022-01-10'));
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_6mo');
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(10);
|
||||
});
|
||||
|
||||
it('Adds 15 to plan.consecutive.gemCapExtra when upgrading from basic_3mo to basic_12mo', async () => {
|
||||
it('Adds 26 to plan.consecutive.gemCapExtra when upgrading from basic_3mo to basic_12mo', async () => {
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_3mo');
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(5);
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(0);
|
||||
|
||||
data.sub.key = 'basic_12mo';
|
||||
data.updatedFrom.key = 'basic_3mo';
|
||||
@@ -1019,28 +823,10 @@ describe('payments/index', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2022-02-05'));
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_12mo');
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(20);
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(26);
|
||||
});
|
||||
|
||||
it('Adds 2 to plan.consecutive.trinkets from basic_earned to basic_6mo', async () => {
|
||||
data.sub.key = 'basic_earned';
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_earned');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(0);
|
||||
|
||||
data.sub.key = 'basic_6mo';
|
||||
data.updatedFrom.key = 'basic_earned';
|
||||
clock.restore();
|
||||
clock = sinon.useFakeTimers(new Date('2022-01-08'));
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_6mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(2);
|
||||
});
|
||||
|
||||
it('Adds 3 to plan.consecutive.trinkets when upgrading from basic_3mo to basic_12mo', async () => {
|
||||
it('Adds 12 to plan.consecutive.trinkets when upgrading from basic_3mo to basic_12mo', async () => {
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
@@ -1054,17 +840,17 @@ describe('payments/index', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2022-01-31'));
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_12mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(4);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(13);
|
||||
});
|
||||
|
||||
it('Adds 2 to plan.consecutive.trinkets when upgrading from basic_6mo to basic_12mo', async () => {
|
||||
it('Adds 12 to plan.consecutive.trinkets when upgrading from basic_6mo to basic_12mo', async () => {
|
||||
data.sub.key = 'basic_6mo';
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_6mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(2);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
|
||||
data.sub.key = 'basic_12mo';
|
||||
data.updatedFrom.key = 'basic_6mo';
|
||||
@@ -1072,35 +858,17 @@ describe('payments/index', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2022-01-28'));
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_12mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(4);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(13);
|
||||
});
|
||||
|
||||
it('Adds 2 to plan.consecutive.trinkets from basic_earned to basic_6mo after initial cycle', async () => {
|
||||
data.sub.key = 'basic_earned';
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_earned');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(0);
|
||||
|
||||
data.sub.key = 'basic_6mo';
|
||||
data.updatedFrom.key = 'basic_earned';
|
||||
clock.restore();
|
||||
clock = sinon.useFakeTimers(new Date('2024-01-08'));
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_6mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(2);
|
||||
});
|
||||
|
||||
it('Adds 2 to plan.consecutive.trinkets when upgrading from basic_6mo to basic_12mo after initial cycle', async () => {
|
||||
it('2 plan.consecutive.trinkets when upgrading from basic_6mo to basic_12mo after initial cycle', async () => {
|
||||
data.sub.key = 'basic_6mo';
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_6mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(2);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
|
||||
data.sub.key = 'basic_12mo';
|
||||
data.updatedFrom.key = 'basic_6mo';
|
||||
@@ -1108,10 +876,10 @@ describe('payments/index', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2022-08-28'));
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_12mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(4);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(13);
|
||||
});
|
||||
|
||||
it('Adds 3 to plan.consecutive.trinkets when upgrading from basic_3mo to basic_12mo after initial cycle', async () => {
|
||||
it('Adds 12 to plan.consecutive.trinkets when upgrading from basic_3mo to basic_12mo after initial cycle', async () => {
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
@@ -1125,11 +893,11 @@ describe('payments/index', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2022-07-31'));
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_12mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(4);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(13);
|
||||
});
|
||||
});
|
||||
context('Upgrades within second half of subscription', () => {
|
||||
it('Adds 10 to plan.consecutive.gemCapExtra from basic_earned to basic_6mo', async () => {
|
||||
it('Adds 0 to plan.consecutive.gemCapExtra from basic_earned to basic_6mo', async () => {
|
||||
data.sub.key = 'basic_earned';
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
@@ -1144,16 +912,16 @@ describe('payments/index', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2022-01-20'));
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_6mo');
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(10);
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(0);
|
||||
});
|
||||
|
||||
it('Adds 20 to plan.consecutive.gemCapExtra when upgrading from basic_3mo to basic_12mo', async () => {
|
||||
it('Adds 26 to plan.consecutive.gemCapExtra when upgrading from basic_3mo to basic_12mo', async () => {
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_3mo');
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(5);
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(0);
|
||||
|
||||
data.sub.key = 'basic_12mo';
|
||||
data.updatedFrom.key = 'basic_3mo';
|
||||
@@ -1161,17 +929,17 @@ describe('payments/index', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2022-02-24'));
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_12mo');
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(25);
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(26);
|
||||
});
|
||||
|
||||
it('Adds 2 to plan.consecutive.trinkets from basic_earned to basic_6mo', async () => {
|
||||
it('Adds 0 to plan.consecutive.trinkets from basic_earned to basic_6mo', async () => {
|
||||
data.sub.key = 'basic_earned';
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_earned');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(0);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
|
||||
data.sub.key = 'basic_6mo';
|
||||
data.updatedFrom.key = 'basic_earned';
|
||||
@@ -1179,17 +947,17 @@ describe('payments/index', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2022-01-28'));
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_6mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(2);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
});
|
||||
|
||||
it('Adds 4 to plan.consecutive.trinkets when upgrading from basic_6mo to basic_12mo', async () => {
|
||||
it('Adds 12 to plan.consecutive.trinkets when upgrading from basic_6mo to basic_12mo', async () => {
|
||||
data.sub.key = 'basic_6mo';
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_6mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(2);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
|
||||
data.sub.key = 'basic_12mo';
|
||||
data.updatedFrom.key = 'basic_6mo';
|
||||
@@ -1197,10 +965,10 @@ describe('payments/index', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2022-05-28'));
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_12mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(6);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(13);
|
||||
});
|
||||
|
||||
it('Adds 4 to plan.consecutive.trinkets when upgrading from basic_3mo to basic_12mo', async () => {
|
||||
it('Adds 12 to plan.consecutive.trinkets when upgrading from basic_3mo to basic_12mo', async () => {
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
@@ -1214,17 +982,17 @@ describe('payments/index', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2022-03-03'));
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_12mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(5);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(13);
|
||||
});
|
||||
|
||||
it('Adds 2 to plan.consecutive.trinkets from basic_earned to basic_6mo after initial cycle', async () => {
|
||||
it('Adds 0 to plan.consecutive.trinkets from basic_earned to basic_6mo after initial cycle', async () => {
|
||||
data.sub.key = 'basic_earned';
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_earned');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(0);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
|
||||
data.sub.key = 'basic_6mo';
|
||||
data.updatedFrom.key = 'basic_earned';
|
||||
@@ -1232,17 +1000,17 @@ describe('payments/index', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2022-05-28'));
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_6mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(2);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
});
|
||||
|
||||
it('Adds 4 to plan.consecutive.trinkets when upgrading from basic_6mo to basic_12mo after initial cycle', async () => {
|
||||
it('Adds 12 to plan.consecutive.trinkets when upgrading from basic_6mo to basic_12mo after initial cycle', async () => {
|
||||
data.sub.key = 'basic_6mo';
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_6mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(2);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(1);
|
||||
|
||||
data.sub.key = 'basic_12mo';
|
||||
data.updatedFrom.key = 'basic_6mo';
|
||||
@@ -1250,10 +1018,10 @@ describe('payments/index', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2023-05-28'));
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_12mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(6);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(13);
|
||||
});
|
||||
|
||||
it('Adds 4 to plan.consecutive.trinkets when upgrading from basic_3mo to basic_12mo after initial cycle', async () => {
|
||||
it('Adds 12 to plan.consecutive.trinkets when upgrading from basic_3mo to basic_12mo after initial cycle', async () => {
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
@@ -1267,7 +1035,7 @@ describe('payments/index', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2023-09-03'));
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_12mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(5);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(13);
|
||||
});
|
||||
});
|
||||
afterEach(async () => {
|
||||
@@ -1277,22 +1045,6 @@ describe('payments/index', () => {
|
||||
});
|
||||
|
||||
context('Downgrades subscription', () => {
|
||||
it('does not remove from plan.consecutive.gemCapExtra from basic_6mo to basic_earned', async () => {
|
||||
data.sub.key = 'basic_6mo';
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_6mo');
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(10);
|
||||
|
||||
data.sub.key = 'basic_earned';
|
||||
data.updatedFrom = { key: 'basic_6mo' };
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_earned');
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(10);
|
||||
});
|
||||
|
||||
it('does not remove from plan.consecutive.gemCapExtra from basic_12mo to basic_3mo', async () => {
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
@@ -1300,28 +1052,12 @@ describe('payments/index', () => {
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_12mo');
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(20);
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(26);
|
||||
|
||||
data.sub.key = 'basic_3mo';
|
||||
data.updatedFrom = { key: 'basic_12mo' };
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(20);
|
||||
});
|
||||
|
||||
it('does not remove from plan.consecutive.trinkets from basic_6mo to basic_earned', async () => {
|
||||
data.sub.key = 'basic_6mo';
|
||||
expect(user.purchased.plan.planId).to.not.exist;
|
||||
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_6mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(2);
|
||||
|
||||
data.sub.key = 'basic_earned';
|
||||
data.updatedFrom = { key: 'basic_6mo' };
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.planId).to.eql('basic_earned');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(2);
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(26);
|
||||
});
|
||||
|
||||
it('does not remove from plan.consecutive.trinkets from basic_12mo to basic_3mo', async () => {
|
||||
@@ -1331,12 +1067,12 @@ describe('payments/index', () => {
|
||||
await api.createSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.planId).to.eql('basic_12mo');
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(4);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(13);
|
||||
|
||||
data.sub.key = 'basic_3mo';
|
||||
data.updatedFrom = { key: 'basic_12mo' };
|
||||
await api.createSubscription(data);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(4);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(13);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1453,6 +1189,32 @@ describe('payments/index', () => {
|
||||
expect(user.purchased.plan.extraMonths).to.eql(0);
|
||||
});
|
||||
|
||||
it('does not reset gemCapExtra', async () => {
|
||||
user.purchased.plan.consecutive.gemCapExtra = 12;
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(12);
|
||||
});
|
||||
|
||||
it('initializes gemCapExtra', async () => {
|
||||
await api.cancelSubscription(data);
|
||||
expect(user.purchased.plan.consecutive.gemCapExtra).to.eql(0);
|
||||
});
|
||||
|
||||
it('initializes hourglasses', async () => {
|
||||
await api.cancelSubscription(data);
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(0);
|
||||
});
|
||||
|
||||
it('does not reset owned hourglasses', async () => {
|
||||
user.purchased.plan.consecutive.trinkets = 12;
|
||||
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
expect(user.purchased.plan.consecutive.trinkets).to.eql(12);
|
||||
});
|
||||
|
||||
it('sends an email', async () => {
|
||||
await api.cancelSubscription(data);
|
||||
|
||||
|
||||
@@ -51,6 +51,7 @@ describe('Stripe - Checkout', () => {
|
||||
gift: undefined,
|
||||
sub: undefined,
|
||||
gemsBlock: gemsBlockKey,
|
||||
server_url: BASE_URL,
|
||||
};
|
||||
|
||||
expect(gems.validateGiftMessage).to.not.be.called;
|
||||
@@ -101,6 +102,7 @@ describe('Stripe - Checkout', () => {
|
||||
gift: JSON.stringify(gift),
|
||||
sub: undefined,
|
||||
gemsBlock: undefined,
|
||||
server_url: BASE_URL,
|
||||
};
|
||||
|
||||
expect(gems.validateGiftMessage).to.be.calledOnce;
|
||||
@@ -155,6 +157,7 @@ describe('Stripe - Checkout', () => {
|
||||
gift: JSON.stringify(gift),
|
||||
sub: undefined,
|
||||
gemsBlock: undefined,
|
||||
server_url: BASE_URL,
|
||||
};
|
||||
|
||||
expect(oneTimePayments.getOneTimePaymentInfo).to.be.calledOnce;
|
||||
@@ -192,6 +195,7 @@ describe('Stripe - Checkout', () => {
|
||||
userId: user._id,
|
||||
gift: undefined,
|
||||
sub: JSON.stringify(sub),
|
||||
server_url: BASE_URL,
|
||||
};
|
||||
|
||||
expect(subscriptions.checkSubData).to.be.calledOnce;
|
||||
@@ -258,6 +262,7 @@ describe('Stripe - Checkout', () => {
|
||||
userId: user._id,
|
||||
gift: undefined,
|
||||
sub: JSON.stringify(sub),
|
||||
server_url: BASE_URL,
|
||||
groupId,
|
||||
};
|
||||
|
||||
@@ -328,8 +333,9 @@ describe('Stripe - Checkout', () => {
|
||||
user.purchased.plan.customerId = customerId;
|
||||
|
||||
const metadata = {
|
||||
userId: user._id,
|
||||
type: 'edit-card-user',
|
||||
userId: user._id,
|
||||
server_url: BASE_URL,
|
||||
};
|
||||
|
||||
const res = await createEditCardCheckoutSession({ user }, stripe);
|
||||
@@ -418,6 +424,7 @@ describe('Stripe - Checkout', () => {
|
||||
const metadata = {
|
||||
userId: user._id,
|
||||
type: 'edit-card-group',
|
||||
server_url: BASE_URL,
|
||||
groupId,
|
||||
};
|
||||
|
||||
@@ -455,6 +462,7 @@ describe('Stripe - Checkout', () => {
|
||||
userId: anotherUser._id,
|
||||
type: 'edit-card-group',
|
||||
groupId,
|
||||
server_url: BASE_URL,
|
||||
};
|
||||
|
||||
const res = await createEditCardCheckoutSession({ user: anotherUser, groupId }, stripe);
|
||||
|
||||
@@ -308,6 +308,7 @@ describe('Stripe - One Time Payments', () => {
|
||||
customerId,
|
||||
paymentMethod: 'Gift',
|
||||
gift,
|
||||
autoRenews: false,
|
||||
gemsBlock: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -173,6 +173,7 @@ describe('Stripe - Subscriptions', () => {
|
||||
paymentMethod: 'Stripe',
|
||||
sub: sinon.match({ ...sub }),
|
||||
groupId: null,
|
||||
autoRenews: true,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -197,6 +198,7 @@ describe('Stripe - Subscriptions', () => {
|
||||
paymentMethod: 'Stripe',
|
||||
sub: sinon.match({ ...sub }),
|
||||
groupId,
|
||||
autoRenews: true,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -231,6 +233,7 @@ describe('Stripe - Subscriptions', () => {
|
||||
paymentMethod: 'Stripe',
|
||||
sub: sinon.match({ ...sub }),
|
||||
groupId,
|
||||
autoRenews: true,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -16,6 +16,7 @@ import * as subscriptions from '../../../../../../website/server/libs/payments/s
|
||||
const { i18n } = common;
|
||||
|
||||
describe('Stripe - Webhooks', () => {
|
||||
const BASE_URL = nconf.get('BASE_URL');
|
||||
const stripe = stripeModule('test');
|
||||
const endpointSecret = nconf.get('STRIPE_WEBHOOKS_ENDPOINT_SECRET');
|
||||
const headers = {};
|
||||
@@ -284,7 +285,9 @@ describe('Stripe - Webhooks', () => {
|
||||
const session = {};
|
||||
|
||||
beforeEach(() => {
|
||||
session.metadata = {};
|
||||
session.metadata = {
|
||||
server_url: BASE_URL,
|
||||
};
|
||||
event = { type: eventType, data: { object: session } };
|
||||
constructEventStub = sandbox.stub(stripe.webhooks, 'constructEvent');
|
||||
constructEventStub.returns(event);
|
||||
|
||||
@@ -54,6 +54,7 @@ describe('rateLimiter middleware', () => {
|
||||
|
||||
it('does not throw when there are available points', async () => {
|
||||
nconfGetStub.withArgs('RATE_LIMITER_ENABLED').returns('true');
|
||||
nconfGetStub.withArgs('RATE_LIMITER_IP_COST').returns(1);
|
||||
const attachRateLimiter = requireAgain(pathToRateLimiter).default;
|
||||
await attachRateLimiter(req, res, next);
|
||||
|
||||
@@ -71,6 +72,7 @@ describe('rateLimiter middleware', () => {
|
||||
|
||||
it('does not throw when an unknown error is thrown by the rate limiter', async () => {
|
||||
nconfGetStub.withArgs('RATE_LIMITER_ENABLED').returns('true');
|
||||
nconfGetStub.withArgs('RATE_LIMITER_IP_COST').returns(1);
|
||||
sandbox.stub(logger, 'error');
|
||||
sandbox.stub(RateLimiterMemory.prototype, 'consume')
|
||||
.returns(Promise.reject(new Error('Unknown error.')));
|
||||
@@ -104,6 +106,7 @@ describe('rateLimiter middleware', () => {
|
||||
it('limits when LIVELINESS_PROBE_KEY is incorrect', async () => {
|
||||
nconfGetStub.withArgs('RATE_LIMITER_ENABLED').returns('true');
|
||||
nconfGetStub.withArgs('LIVELINESS_PROBE_KEY').returns('abc');
|
||||
nconfGetStub.withArgs('RATE_LIMITER_IP_COST').returns(1);
|
||||
const attachRateLimiter = requireAgain(pathToRateLimiter).default;
|
||||
|
||||
req.query.liveliness = 'das';
|
||||
@@ -120,6 +123,7 @@ describe('rateLimiter middleware', () => {
|
||||
it('limits when LIVELINESS_PROBE_KEY is not set', async () => {
|
||||
nconfGetStub.withArgs('RATE_LIMITER_ENABLED').returns('true');
|
||||
nconfGetStub.withArgs('LIVELINESS_PROBE_KEY').returns(undefined);
|
||||
nconfGetStub.withArgs('RATE_LIMITER_IP_COST').returns(1);
|
||||
const attachRateLimiter = requireAgain(pathToRateLimiter).default;
|
||||
|
||||
await attachRateLimiter(req, res, next);
|
||||
@@ -135,6 +139,7 @@ describe('rateLimiter middleware', () => {
|
||||
it('throws when LIVELINESS_PROBE_KEY is blank', async () => {
|
||||
nconfGetStub.withArgs('RATE_LIMITER_ENABLED').returns('true');
|
||||
nconfGetStub.withArgs('LIVELINESS_PROBE_KEY').returns('');
|
||||
nconfGetStub.withArgs('RATE_LIMITER_IP_COST').returns(1);
|
||||
const attachRateLimiter = requireAgain(pathToRateLimiter).default;
|
||||
|
||||
req.query.liveliness = '';
|
||||
@@ -150,6 +155,7 @@ describe('rateLimiter middleware', () => {
|
||||
|
||||
it('throws when there are no available points remaining', async () => {
|
||||
nconfGetStub.withArgs('RATE_LIMITER_ENABLED').returns('true');
|
||||
nconfGetStub.withArgs('RATE_LIMITER_IP_COST').returns(1);
|
||||
const attachRateLimiter = requireAgain(pathToRateLimiter).default;
|
||||
|
||||
// call for 31 times
|
||||
@@ -173,6 +179,7 @@ describe('rateLimiter middleware', () => {
|
||||
|
||||
it('uses the user id if supplied or the ip address', async () => {
|
||||
nconfGetStub.withArgs('RATE_LIMITER_ENABLED').returns('true');
|
||||
nconfGetStub.withArgs('RATE_LIMITER_IP_COST').returns(1);
|
||||
const attachRateLimiter = requireAgain(pathToRateLimiter).default;
|
||||
|
||||
req.ip = 1;
|
||||
@@ -199,4 +206,51 @@ describe('rateLimiter middleware', () => {
|
||||
'X-RateLimit-Reset': sinon.match(Date),
|
||||
});
|
||||
});
|
||||
|
||||
it('applies increased cost for registration calls with and without user id', async () => {
|
||||
nconfGetStub.withArgs('RATE_LIMITER_ENABLED').returns('true');
|
||||
nconfGetStub.withArgs('RATE_LIMITER_REGISTRATION_COST').returns(3);
|
||||
const attachRateLimiter = requireAgain(pathToRateLimiter).default;
|
||||
req.path = '/api/v4/user/auth/local/register';
|
||||
|
||||
req.ip = 1;
|
||||
await attachRateLimiter(req, res, next);
|
||||
|
||||
req.headers['x-api-user'] = 'user-1';
|
||||
await attachRateLimiter(req, res, next);
|
||||
await attachRateLimiter(req, res, next);
|
||||
|
||||
// user id an ip are counted as separate sources
|
||||
expect(res.set).to.have.been.calledWithMatch({
|
||||
'X-RateLimit-Limit': 30,
|
||||
'X-RateLimit-Remaining': 27, // 2 calls with user id
|
||||
'X-RateLimit-Reset': sinon.match(Date),
|
||||
});
|
||||
|
||||
req.headers['x-api-user'] = undefined;
|
||||
await attachRateLimiter(req, res, next);
|
||||
await attachRateLimiter(req, res, next);
|
||||
|
||||
expect(res.set).to.have.been.calledWithMatch({
|
||||
'X-RateLimit-Limit': 30,
|
||||
'X-RateLimit-Remaining': 24, // 3 calls with only ip
|
||||
'X-RateLimit-Reset': sinon.match(Date),
|
||||
});
|
||||
});
|
||||
|
||||
it('applies increased cost for unauthenticated API calls', async () => {
|
||||
nconfGetStub.withArgs('RATE_LIMITER_ENABLED').returns('true');
|
||||
nconfGetStub.withArgs('RATE_LIMITER_IP_COST').returns(10);
|
||||
const attachRateLimiter = requireAgain(pathToRateLimiter).default;
|
||||
|
||||
req.ip = 1;
|
||||
await attachRateLimiter(req, res, next);
|
||||
await attachRateLimiter(req, res, next);
|
||||
|
||||
expect(res.set).to.have.been.calledWithMatch({
|
||||
'X-RateLimit-Limit': 30,
|
||||
'X-RateLimit-Remaining': 10,
|
||||
'X-RateLimit-Reset': sinon.match(Date),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
73
test/api/v3/integration/debug/POST-debug_boss-rage.test.js
Normal file
@@ -0,0 +1,73 @@
|
||||
import nconf from 'nconf';
|
||||
import {
|
||||
generateUser,
|
||||
createAndPopulateGroup,
|
||||
} from '../../../../helpers/api-integration/v3';
|
||||
|
||||
describe('POST /debug/boss-rage', () => {
|
||||
let user;
|
||||
let nconfStub;
|
||||
|
||||
beforeEach(async () => {
|
||||
user = await generateUser();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
nconfStub = sandbox.stub(nconf, 'get');
|
||||
nconfStub.withArgs('DEBUG_ENABLED').returns(true);
|
||||
nconfStub.withArgs('BASE_URL').returns('https://example.com');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
nconfStub.restore();
|
||||
});
|
||||
|
||||
it('errors if user is not in a party', async () => {
|
||||
await expect(user.post('/debug/boss-rage'))
|
||||
.to.eventually.be.rejected.and.deep.equal({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: 'User not in a party.',
|
||||
});
|
||||
});
|
||||
|
||||
it('returns error when not in production mode', async () => {
|
||||
nconfStub.withArgs('DEBUG_ENABLED').returns(false);
|
||||
|
||||
await expect(user.post('/debug/boss-rage'))
|
||||
.to.eventually.be.rejected.and.deep.equal({
|
||||
code: 404,
|
||||
error: 'NotFound',
|
||||
message: 'Not found.',
|
||||
});
|
||||
});
|
||||
|
||||
context('user is in a party', async () => {
|
||||
let party;
|
||||
|
||||
beforeEach(async () => {
|
||||
const { group, groupLeader } = await createAndPopulateGroup({
|
||||
groupDetails: {
|
||||
name: 'Test Party',
|
||||
type: 'party',
|
||||
},
|
||||
members: 2,
|
||||
});
|
||||
party = group;
|
||||
user = groupLeader;
|
||||
});
|
||||
|
||||
it('increases boss rage to 50', async () => {
|
||||
await user.post('/debug/boss-rage');
|
||||
await party.sync();
|
||||
expect(party.quest.progress.rage).to.eql(50);
|
||||
});
|
||||
|
||||
it('increases boss rage to 100', async () => {
|
||||
await user.post('/debug/boss-rage');
|
||||
await user.post('/debug/boss-rage');
|
||||
await party.sync();
|
||||
expect(party.quest.progress.rage).to.eql(100);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -34,9 +34,11 @@ describe('POST /debug/jump-time', () => {
|
||||
expect(resultDate.getMonth()).to.eql(today.getMonth());
|
||||
expect(resultDate.getFullYear()).to.eql(today.getFullYear());
|
||||
const newResultDate = new Date((await user.post('/debug/jump-time', { offsetDays: 1 })).time);
|
||||
expect(newResultDate.getDate()).to.eql(today.getDate() + 1);
|
||||
expect(newResultDate.getMonth()).to.eql(today.getMonth());
|
||||
expect(newResultDate.getFullYear()).to.eql(today.getFullYear());
|
||||
const tomorrow = new Date(today.valueOf());
|
||||
tomorrow.setDate(today.getDate() + 1);
|
||||
expect(newResultDate.getDate()).to.eql(tomorrow.getDate());
|
||||
expect(newResultDate.getMonth()).to.eql(tomorrow.getMonth());
|
||||
expect(newResultDate.getFullYear()).to.eql(tomorrow.getFullYear());
|
||||
});
|
||||
|
||||
it('jumps back', async () => {
|
||||
@@ -45,9 +47,11 @@ describe('POST /debug/jump-time', () => {
|
||||
expect(resultDate.getMonth()).to.eql(today.getMonth());
|
||||
expect(resultDate.getFullYear()).to.eql(today.getFullYear());
|
||||
const newResultDate = new Date((await user.post('/debug/jump-time', { offsetDays: -1 })).time);
|
||||
expect(newResultDate.getDate()).to.eql(today.getDate() - 1);
|
||||
expect(newResultDate.getMonth()).to.eql(today.getMonth());
|
||||
expect(newResultDate.getFullYear()).to.eql(today.getFullYear());
|
||||
const yesterday = new Date(today.valueOf());
|
||||
yesterday.setDate(today.getDate() - 1);
|
||||
expect(newResultDate.getDate()).to.eql(yesterday.getDate());
|
||||
expect(newResultDate.getMonth()).to.eql(yesterday.getMonth());
|
||||
expect(newResultDate.getFullYear()).to.eql(yesterday.getFullYear());
|
||||
});
|
||||
|
||||
it('can jump a lot', async () => {
|
||||
@@ -55,7 +59,7 @@ describe('POST /debug/jump-time', () => {
|
||||
expect(resultDate.getDate()).to.eql(today.getDate());
|
||||
expect(resultDate.getMonth()).to.eql(today.getMonth());
|
||||
expect(resultDate.getFullYear()).to.eql(today.getFullYear());
|
||||
const newResultDate = new Date((await user.post('/debug/jump-time', { offsetDays: 355 })).time);
|
||||
const newResultDate = new Date((await user.post('/debug/jump-time', { offsetDays: 365 })).time);
|
||||
expect(newResultDate.getFullYear()).to.eql(today.getFullYear() + 1);
|
||||
});
|
||||
|
||||
|
||||
@@ -85,22 +85,6 @@ describe('POST /group/:groupId/join', () => {
|
||||
await expect(user.get('/user')).to.eventually.have.nested.property('items.quests.basilist', 1);
|
||||
});
|
||||
|
||||
it('notifies inviting user that their invitation was accepted', async () => {
|
||||
await invitedUser.post(`/groups/${guild._id}/join`);
|
||||
|
||||
const inviter = await user.get('/user');
|
||||
const expectedData = {
|
||||
headerText: t('invitationAcceptedHeader'),
|
||||
bodyText: t('invitationAcceptedBody', {
|
||||
username: invitedUser.auth.local.username,
|
||||
groupName: guild.name,
|
||||
}),
|
||||
};
|
||||
|
||||
expect(inviter.notifications[1].type).to.eql('GROUP_INVITE_ACCEPTED');
|
||||
expect(inviter.notifications[1].data).to.eql(expectedData);
|
||||
});
|
||||
|
||||
it('awards Joined Guild achievement', async () => {
|
||||
await invitedUser.post(`/groups/${guild._id}/join`);
|
||||
|
||||
@@ -155,23 +139,6 @@ describe('POST /group/:groupId/join', () => {
|
||||
await expect(invitedUser.get('/user')).to.eventually.have.nested.property('party._id', party._id);
|
||||
});
|
||||
|
||||
it('notifies inviting user that their invitation was accepted', async () => {
|
||||
await invitedUser.post(`/groups/${party._id}/join`);
|
||||
|
||||
const inviter = await user.get('/user');
|
||||
|
||||
const expectedData = {
|
||||
headerText: t('invitationAcceptedHeader'),
|
||||
bodyText: t('invitationAcceptedBody', {
|
||||
username: invitedUser.auth.local.username,
|
||||
groupName: party.name,
|
||||
}),
|
||||
};
|
||||
|
||||
expect(inviter.notifications[0].type).to.eql('GROUP_INVITE_ACCEPTED');
|
||||
expect(inviter.notifications[0].data).to.eql(expectedData);
|
||||
});
|
||||
|
||||
it('clears invitation from user when joining party', async () => {
|
||||
await invitedUser.post(`/groups/${party._id}/join`);
|
||||
|
||||
|
||||
@@ -125,6 +125,90 @@ describe('POST /tasks/:id/score/:direction', () => {
|
||||
expect(body.finalLvl).to.eql(user.stats.lvl);
|
||||
});
|
||||
});
|
||||
|
||||
context('handles drops', async () => {
|
||||
let randomStub;
|
||||
|
||||
afterEach(() => {
|
||||
randomStub.restore();
|
||||
});
|
||||
it('gives user a drop', async () => {
|
||||
user = await generateUser({
|
||||
'stats.gp': 100,
|
||||
'achievements.completedTask': true,
|
||||
'items.eggs': {
|
||||
Wolf: 1,
|
||||
},
|
||||
});
|
||||
randomStub = sandbox.stub(Math, 'random').returns(0.1);
|
||||
const task = await user.post('/tasks/user', {
|
||||
text: 'test habit',
|
||||
type: 'habit',
|
||||
});
|
||||
|
||||
const res = await user.post(`/tasks/${task.id}/score/up`);
|
||||
expect(res._tmp.drop).to.be.ok;
|
||||
});
|
||||
|
||||
it('does not give a drop when non-sub drop cap is reached', async () => {
|
||||
user = await generateUser({
|
||||
'stats.gp': 100,
|
||||
'achievements.completedTask': true,
|
||||
'items.eggs': {
|
||||
Wolf: 1,
|
||||
},
|
||||
'items.lastDrop.count': 5,
|
||||
});
|
||||
randomStub = sandbox.stub(Math, 'random').returns(0.1);
|
||||
const task = await user.post('/tasks/user', {
|
||||
text: 'test habit',
|
||||
type: 'habit',
|
||||
});
|
||||
|
||||
const res = await user.post(`/tasks/${task.id}/score/up`);
|
||||
expect(res._tmp.drop).to.be.undefined;
|
||||
});
|
||||
|
||||
it('gives a drop when subscriber is over regular cap but under subscriber cap', async () => {
|
||||
user = await generateUser({
|
||||
'stats.gp': 100,
|
||||
'achievements.completedTask': true,
|
||||
'items.eggs': {
|
||||
Wolf: 1,
|
||||
},
|
||||
'items.lastDrop.count': 6,
|
||||
'purchased.plan.customerId': '123',
|
||||
});
|
||||
randomStub = sandbox.stub(Math, 'random').returns(0.1);
|
||||
const task = await user.post('/tasks/user', {
|
||||
text: 'test habit',
|
||||
type: 'habit',
|
||||
});
|
||||
|
||||
const res = await user.post(`/tasks/${task.id}/score/up`);
|
||||
expect(res._tmp.drop).to.be.ok;
|
||||
});
|
||||
|
||||
it('does not give a drop when subscriber is at subscriber drop cap', async () => {
|
||||
user = await generateUser({
|
||||
'stats.gp': 100,
|
||||
'achievements.completedTask': true,
|
||||
'items.eggs': {
|
||||
Wolf: 1,
|
||||
},
|
||||
'items.lastDrop.count': 10,
|
||||
'purchased.plan.customerId': '123',
|
||||
});
|
||||
randomStub = sandbox.stub(Math, 'random').returns(0.1);
|
||||
const task = await user.post('/tasks/user', {
|
||||
text: 'test habit',
|
||||
type: 'habit',
|
||||
});
|
||||
|
||||
const res = await user.post(`/tasks/${task.id}/score/up`);
|
||||
expect(res._tmp.drop).to.be.undefined;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
context('todos', () => {
|
||||
|
||||
@@ -105,9 +105,9 @@ describe('POST /tasks/:taskId/assign/:memberId', () => {
|
||||
|
||||
const groupTask = await user.get(`/tasks/group/${guild._id}`);
|
||||
|
||||
expect(member.notifications.length).to.equal(2);
|
||||
expect(member.notifications[1].type).to.equal('GROUP_TASK_ASSIGNED');
|
||||
expect(member.notifications[1].taskId).to.equal(groupTask._id);
|
||||
const lastNotification = member.notifications[member.notifications.length - 1];
|
||||
expect(lastNotification.type).to.equal('GROUP_TASK_ASSIGNED');
|
||||
expect(lastNotification.taskId).to.equal(groupTask._id);
|
||||
});
|
||||
|
||||
it('assigns a task to multiple users', async () => {
|
||||
|
||||
@@ -89,10 +89,12 @@ describe('POST /tasks/:taskId/unassign/:memberId', () => {
|
||||
});
|
||||
|
||||
it('removes task assignment notification from unassigned user', async () => {
|
||||
await member.sync();
|
||||
const oldNotificationCount = member.notifications.length;
|
||||
await user.post(`/tasks/${task._id}/unassign/${member._id}`);
|
||||
|
||||
await member.sync();
|
||||
expect(member.notifications.length).to.equal(1); // mystery items
|
||||
expect(member.notifications.length).to.equal(oldNotificationCount - 1);
|
||||
});
|
||||
|
||||
it('unassigns a user and only that user from a task', async () => {
|
||||
|
||||
@@ -31,7 +31,7 @@ describe('POST /user/buy-mystery-set/:key', () => {
|
||||
|
||||
expect(res.data).to.eql({
|
||||
items: JSON.parse(JSON.stringify(user.items)), // otherwise dates can't be compared
|
||||
purchasedPlanConsecutive: user.purchased.plan.consecutive,
|
||||
purchasedPlanConsecutive: JSON.parse(JSON.stringify(user.purchased.plan.consecutive)),
|
||||
});
|
||||
expect(res.message).to.equal(t('hourglassPurchaseSet'));
|
||||
});
|
||||
|
||||
@@ -123,7 +123,7 @@ describe('GET /world-state', () => {
|
||||
|
||||
const res = await requester().get('/world-state');
|
||||
|
||||
expect(res.npcImageSuffix).to.equal('winter');
|
||||
expect(res.npcImageSuffix).to.equal('fall');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -40,6 +40,24 @@ describe('GET /user', () => {
|
||||
expect(returnedUser.stats).to.not.exist;
|
||||
});
|
||||
|
||||
it('returns when ALWAYS_LOADED paths are requested', async () => {
|
||||
const returnedUser = await user.get('/user?userFields=_id,notifications,preferences,auth,flags,permissions');
|
||||
|
||||
expect(returnedUser._id).to.equal(user._id);
|
||||
expect(returnedUser.notifications).to.exist;
|
||||
expect(returnedUser.preferences).to.exist;
|
||||
expect(returnedUser.auth).to.exist;
|
||||
expect(returnedUser.flags).to.exist;
|
||||
expect(returnedUser.permissions).to.exist;
|
||||
});
|
||||
|
||||
it('returns when subpaths paths are requested', async () => {
|
||||
const returnedUser = await user.get('/user?userFields=auth.local.username');
|
||||
|
||||
expect(returnedUser._id).to.equal(user._id);
|
||||
expect(returnedUser.auth.local.username).to.exist;
|
||||
});
|
||||
|
||||
it('does not return requested private properties', async () => {
|
||||
const returnedUser = await user.get('/user?userFields=apiToken,secret.text');
|
||||
|
||||
|
||||
@@ -183,8 +183,6 @@ describe('cron utility functions', () => {
|
||||
});
|
||||
|
||||
describe('getPlanContext', () => {
|
||||
const now = new Date(2022, 5, 1);
|
||||
|
||||
function baseUserData (count, offset, planId) {
|
||||
return {
|
||||
purchased: {
|
||||
@@ -192,7 +190,7 @@ describe('cron utility functions', () => {
|
||||
consecutive: {
|
||||
count,
|
||||
offset,
|
||||
gemCapExtra: 25,
|
||||
gemCapExtra: 26,
|
||||
trinkets: 19,
|
||||
},
|
||||
quantity: 1,
|
||||
@@ -213,52 +211,19 @@ describe('cron utility functions', () => {
|
||||
};
|
||||
}
|
||||
|
||||
it('monthly plan, next date in 3 months', () => {
|
||||
it('elapsedMonths is 0 if its the same month', () => {
|
||||
const user = baseUserData(60, 0, 'group_plan_auto');
|
||||
user.purchased.plan.perkMonthCount = 0;
|
||||
|
||||
const planContext = getPlanContext(user, now);
|
||||
|
||||
expect(planContext.nextHourglassDate)
|
||||
.to.be.sameMoment('2022-08-10T02:00:00.144Z');
|
||||
const planContext = getPlanContext(user, new Date(2022, 4, 20));
|
||||
expect(planContext.elapsedMonths).to.equal(0);
|
||||
});
|
||||
|
||||
it('monthly plan, next date in 1 month', () => {
|
||||
const user = baseUserData(62, 0, 'group_plan_auto');
|
||||
user.purchased.plan.perkMonthCount = 2;
|
||||
it('elapsedMonths is 1 after one month', () => {
|
||||
const user = baseUserData(60, 0, 'group_plan_auto');
|
||||
|
||||
const planContext = getPlanContext(user, now);
|
||||
const planContext = getPlanContext(user, new Date(2022, 5, 11));
|
||||
|
||||
expect(planContext.nextHourglassDate)
|
||||
.to.be.sameMoment('2022-06-10T02:00:00.144Z');
|
||||
});
|
||||
|
||||
it('multi-month plan, no offset', () => {
|
||||
const user = baseUserData(60, 0, 'basic_3mo');
|
||||
|
||||
const planContext = getPlanContext(user, now);
|
||||
|
||||
expect(planContext.nextHourglassDate)
|
||||
.to.be.sameMoment('2022-06-10T02:00:00.144Z');
|
||||
});
|
||||
|
||||
it('multi-month plan with offset', () => {
|
||||
const user = baseUserData(60, 1, 'basic_3mo');
|
||||
|
||||
const planContext = getPlanContext(user, now);
|
||||
|
||||
expect(planContext.nextHourglassDate)
|
||||
.to.be.sameMoment('2022-07-10T02:00:00.144Z');
|
||||
});
|
||||
|
||||
it('multi-month plan with perk count', () => {
|
||||
const user = baseUserData(60, 1, 'basic_3mo');
|
||||
user.purchased.plan.perkMonthCount = 2;
|
||||
|
||||
const planContext = getPlanContext(user, now);
|
||||
|
||||
expect(planContext.nextHourglassDate)
|
||||
.to.be.sameMoment('2022-07-10T02:00:00.144Z');
|
||||
expect(planContext.elapsedMonths).to.equal(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -47,15 +47,17 @@ describe('shops', () => {
|
||||
|
||||
describe('premium hatching potions', () => {
|
||||
it('contains current scheduled premium hatching potions', async () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-04-01'));
|
||||
clock = sinon.useFakeTimers(new Date('2024-04-01T09:00:00.000Z'));
|
||||
const potions = shared.shops.getMarketCategories(user).find(x => x.identifier === 'premiumHatchingPotions');
|
||||
expect(potions.items.length).to.eql(2);
|
||||
expect(potions.items.length).to.eql(3);
|
||||
});
|
||||
|
||||
it('does not contain past scheduled premium hatching potions', async () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-04-01T09:00:00.000Z'));
|
||||
const potions = shared.shops.getMarketCategories(user).find(x => x.identifier === 'premiumHatchingPotions');
|
||||
expect(potions.items.filter(x => x.key === 'Aquatic' || x.key === 'Celestial').length).to.eql(0);
|
||||
expect(potions.items.filter(x => x.key === 'Aquatic' || x.key === 'Celestial').length, 'Aquatic or Celestial found').to.eql(0);
|
||||
});
|
||||
|
||||
it('returns end date for scheduled premium potions', async () => {
|
||||
const potions = shared.shops.getMarketCategories(user).find(x => x.identifier === 'premiumHatchingPotions');
|
||||
potions.items.forEach(potion => {
|
||||
@@ -73,9 +75,9 @@ describe('shops', () => {
|
||||
});
|
||||
|
||||
it('does not contain locked quest premium hatching potions', async () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-04-01'));
|
||||
clock = sinon.useFakeTimers(new Date('2024-04-01T09:00:00.000Z'));
|
||||
const potions = shared.shops.getMarketCategories(user).find(x => x.identifier === 'premiumHatchingPotions');
|
||||
expect(potions.items.length).to.eql(2);
|
||||
expect(potions.items.length).to.eql(3);
|
||||
expect(potions.items.filter(x => x.key === 'Bronze' || x.key === 'BlackPearl').length).to.eql(0);
|
||||
});
|
||||
|
||||
@@ -341,6 +343,16 @@ describe('shops', () => {
|
||||
const backgrounds = shopCategories.find(cat => cat.identifier === 'backgrounds').items;
|
||||
expect(backgrounds.length).to.be.greaterThan(0);
|
||||
});
|
||||
|
||||
it('does not add an end date to steampunk gear', () => {
|
||||
const categories = shopCategories.filter(cat => cat.identifier.startsWith('30'));
|
||||
categories.forEach(category => {
|
||||
expect(category.end).to.not.exist;
|
||||
category.items.forEach(item => {
|
||||
expect(item.end).to.not.exist;
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('customizationShop', () => {
|
||||
|
||||
@@ -233,6 +233,17 @@ describe('shared.ops.purchase', () => {
|
||||
expect(user.items.hatchingPotions[key]).to.eql(1);
|
||||
});
|
||||
|
||||
it('purchases event hatching potion', async () => {
|
||||
clock.restore();
|
||||
clock = sandbox.useFakeTimers(moment('2022-04-10').valueOf());
|
||||
const type = 'hatchingPotions';
|
||||
const key = 'Veggie';
|
||||
|
||||
await purchase(user, { params: { type, key } });
|
||||
|
||||
expect(user.items.hatchingPotions[key]).to.eql(1);
|
||||
});
|
||||
|
||||
it('purchases hatching potion if user completed quest', async () => {
|
||||
const type = 'hatchingPotions';
|
||||
const key = 'Bronze';
|
||||
|
||||
@@ -10,7 +10,7 @@ describe('events', () => {
|
||||
});
|
||||
|
||||
it('returns empty array when no events are active', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-01-06'));
|
||||
clock = sinon.useFakeTimers(new Date('2024-01-08'));
|
||||
const events = getRepeatingEvents();
|
||||
expect(events).to.be.empty;
|
||||
});
|
||||
@@ -27,14 +27,14 @@ describe('events', () => {
|
||||
it('returns nye event at beginning of the year', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2025-01-01'));
|
||||
const events = getRepeatingEvents();
|
||||
expect(events).to.have.length(1);
|
||||
expect(events).to.have.length(2);
|
||||
expect(events[0].key).to.equal('nye');
|
||||
});
|
||||
|
||||
it('returns nye event at end of the year', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-12-30'));
|
||||
const events = getRepeatingEvents();
|
||||
expect(events).to.have.length(1);
|
||||
expect(events).to.have.length(2);
|
||||
expect(events[0].key).to.equal('nye');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -72,7 +72,7 @@ describe('food', () => {
|
||||
});
|
||||
|
||||
it('sets canDrop for pie if it is pie season', () => {
|
||||
clock = sinon.useFakeTimers(new Date(2024, 2, 14));
|
||||
clock = sinon.useFakeTimers(new Date(2024, 2, 15));
|
||||
const datedContent = require('../../website/common/script/content').default;
|
||||
each(datedContent.food, foodItem => {
|
||||
if (foodItem.key.indexOf('Pie_') !== -1) {
|
||||
|
||||
@@ -42,23 +42,23 @@ describe('content index', () => {
|
||||
expect(Object.keys(juneGear).length, '').to.equal(Object.keys(julyGear).length - 3);
|
||||
});
|
||||
|
||||
it('Releases pets gear when appropriate without needing restarting', () => {
|
||||
it('Releases pets when appropriate without needing restarting', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-06-20'));
|
||||
const junePets = content.petInfo;
|
||||
expect(junePets['Chameleon-Base']).to.not.exist;
|
||||
clock.restore();
|
||||
clock = sinon.useFakeTimers(new Date('2024-07-10'));
|
||||
clock = sinon.useFakeTimers(new Date('2024-07-18'));
|
||||
const julyPets = content.petInfo;
|
||||
expect(julyPets['Chameleon-Base']).to.exist;
|
||||
expect(Object.keys(junePets).length, '').to.equal(Object.keys(julyPets).length - 10);
|
||||
});
|
||||
|
||||
it('Releases mounts gear when appropriate without needing restarting', () => {
|
||||
it('Releases mounts when appropriate without needing restarting', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-06-20'));
|
||||
const juneMounts = content.mountInfo;
|
||||
expect(juneMounts['Chameleon-Base']).to.not.exist;
|
||||
clock.restore();
|
||||
clock = sinon.useFakeTimers(new Date('2024-07-10'));
|
||||
clock = sinon.useFakeTimers(new Date('2024-07-18'));
|
||||
const julyMounts = content.mountInfo;
|
||||
expect(julyMounts['Chameleon-Base']).to.exist;
|
||||
expect(Object.keys(juneMounts).length, '').to.equal(Object.keys(julyMounts).length - 10);
|
||||
@@ -131,7 +131,7 @@ describe('content index', () => {
|
||||
});
|
||||
|
||||
it('marks pie as buyable and droppable during pi day', () => {
|
||||
clock = sinon.useFakeTimers(new Date('2024-03-14'));
|
||||
clock = sinon.useFakeTimers(new Date('2024-03-15'));
|
||||
const { food } = content;
|
||||
Object.keys(food).forEach(key => {
|
||||
if (key === 'Saddle') {
|
||||
|
||||
42
test/content/quests.test.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import {
|
||||
each,
|
||||
} from 'lodash';
|
||||
import {
|
||||
expectValidTranslationString,
|
||||
} from '../helpers/content.helper';
|
||||
|
||||
import { quests } from '../../website/common/script/content/quests';
|
||||
|
||||
describe('quests', () => {
|
||||
let clock;
|
||||
|
||||
afterEach(() => {
|
||||
if (clock) {
|
||||
clock.restore();
|
||||
}
|
||||
});
|
||||
|
||||
it('contains basic information about each quest', () => {
|
||||
each(quests, (quest, key) => {
|
||||
expectValidTranslationString(quest.text);
|
||||
expectValidTranslationString(quest.notes);
|
||||
expectValidTranslationString(quest.completion);
|
||||
expect(quest.key, key).to.equal(key);
|
||||
expect(quest.category, key).to.be.a('string');
|
||||
if (quest.boss) {
|
||||
expectValidTranslationString(quest.boss.name);
|
||||
expect(quest.boss.hp, key).to.be.a('number');
|
||||
expect(quest.boss.str, key).to.be.a('number');
|
||||
}
|
||||
expect(quest.drop).to.be.an('object');
|
||||
expect(quest.drop.gp, key).to.be.a('number');
|
||||
expect(quest.drop.exp, key).to.be.a('number');
|
||||
if (quest.drop.items) {
|
||||
quest.drop.items.forEach(drop => {
|
||||
expectValidTranslationString(drop.text);
|
||||
expect(drop.type, key).to.exist;
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -19,8 +19,8 @@ describe('releaseDates', () => {
|
||||
});
|
||||
describe('armoire', () => {
|
||||
it('should only contain valid armoire names', () => {
|
||||
const lastReleaseDate = maxBy(Object.values(ARMOIRE_RELEASE_DATES), value => new Date(`${value.year}-${value.month + 1}-20`));
|
||||
clock = sinon.useFakeTimers(new Date(`${lastReleaseDate.year}-${lastReleaseDate.month + 1}-20`));
|
||||
const lastReleaseDate = maxBy(Object.values(ARMOIRE_RELEASE_DATES), value => new Date(`${value.year}-${value.month}-22`));
|
||||
clock = sinon.useFakeTimers(new Date(`${lastReleaseDate.year}-${lastReleaseDate.month}-22`));
|
||||
Object.keys(ARMOIRE_RELEASE_DATES).forEach(key => {
|
||||
expect(find(armoire.all, { set: key }), `${key} is not a valid armoire set`).to.exist;
|
||||
});
|
||||
@@ -40,8 +40,8 @@ describe('releaseDates', () => {
|
||||
|
||||
describe('eggs', () => {
|
||||
it('should only contain valid egg names', () => {
|
||||
const lastReleaseDate = maxBy(Object.values(EGGS_RELEASE_DATES), value => new Date(`${value.year}-${value.month + 1}-${value.day}`));
|
||||
clock = sinon.useFakeTimers(new Date(`${lastReleaseDate.year}-${lastReleaseDate.month + 1}-${lastReleaseDate.day}`));
|
||||
const lastReleaseDate = maxBy(Object.values(EGGS_RELEASE_DATES), value => new Date(`${value.year}-${value.month}-${value.day}`));
|
||||
clock = sinon.useFakeTimers(new Date(`${lastReleaseDate.year}-${lastReleaseDate.month}-${lastReleaseDate.day + 1}`));
|
||||
Object.keys(EGGS_RELEASE_DATES).forEach(key => {
|
||||
expect(eggs.all[key], `${key} is not a valid egg name`).to.exist;
|
||||
});
|
||||
@@ -61,8 +61,8 @@ describe('releaseDates', () => {
|
||||
|
||||
describe('hatchingPotions', () => {
|
||||
it('should only contain valid potion names', () => {
|
||||
const lastReleaseDate = maxBy(Object.values(HATCHING_POTIONS_RELEASE_DATES), value => new Date(`${value.year}-${value.month + 1}-${value.day}`));
|
||||
clock = sinon.useFakeTimers(new Date(`${lastReleaseDate.year}-${lastReleaseDate.month + 1}-${lastReleaseDate.day}`));
|
||||
const lastReleaseDate = maxBy(Object.values(HATCHING_POTIONS_RELEASE_DATES), value => new Date(`${value.year}-${value.month}-${value.day}`));
|
||||
clock = sinon.useFakeTimers(new Date(`${lastReleaseDate.year}-${lastReleaseDate.month}-${lastReleaseDate.day + 1}`));
|
||||
Object.keys(HATCHING_POTIONS_RELEASE_DATES).forEach(key => {
|
||||
expect(hatchingPotions.all[key], `${key} is not a valid potion name`).to.exist;
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// eslint-disable-next-line max-len
|
||||
import maxBy from 'lodash/maxBy';
|
||||
import moment from 'moment';
|
||||
import nconf from 'nconf';
|
||||
import {
|
||||
@@ -10,6 +11,7 @@ import QUEST_BUNDLES from '../../website/common/script/content/bundles';
|
||||
import potions from '../../website/common/script/content/hatching-potions';
|
||||
import SPELLS from '../../website/common/script/content/spells';
|
||||
import QUEST_SEASONAL from '../../website/common/script/content/quests/seasonal';
|
||||
import { HATCHING_POTIONS_RELEASE_DATES } from '../../website/common/script/content/constants/releaseDates';
|
||||
|
||||
function validateMatcher (matcher, checkedDate) {
|
||||
expect(matcher.end).to.be.a('date');
|
||||
@@ -18,12 +20,19 @@ function validateMatcher (matcher, checkedDate) {
|
||||
|
||||
describe('Content Schedule', () => {
|
||||
let switchoverTime;
|
||||
let clock;
|
||||
|
||||
beforeEach(() => {
|
||||
switchoverTime = nconf.get('CONTENT_SWITCHOVER_TIME_OFFSET') || 0;
|
||||
clearCachedMatchers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (clock) {
|
||||
clock.restore();
|
||||
}
|
||||
});
|
||||
|
||||
it('assembles scheduled items on january 15th', () => {
|
||||
const date = new Date('2024-01-15');
|
||||
const matchers = getAllScheduleMatchingGroups(date);
|
||||
@@ -105,8 +114,14 @@ describe('Content Schedule', () => {
|
||||
expect(matchers.backgrounds.end).to.eql(moment.utc(`2024-05-07T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||
});
|
||||
|
||||
it('sets the end date if its on the release day', () => {
|
||||
const date = new Date('2024-05-07T07:00:00.000Z');
|
||||
it('sets the end date if its on the release day before switchover', () => {
|
||||
const date = new Date('2024-05-07T07:00:00.000+00:00');
|
||||
const matchers = getAllScheduleMatchingGroups(date);
|
||||
expect(matchers.backgrounds.end).to.eql(moment.utc(`2024-05-07T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||
});
|
||||
|
||||
it('sets the end date if its on the release day after switchover', () => {
|
||||
const date = new Date('2024-05-07T09:00:00.000+00:00');
|
||||
const matchers = getAllScheduleMatchingGroups(date);
|
||||
expect(matchers.backgrounds.end).to.eql(moment.utc(`2024-06-07T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||
});
|
||||
@@ -123,12 +138,60 @@ describe('Content Schedule', () => {
|
||||
expect(matchers.seasonalGear.end).to.eql(moment.utc(`2024-06-21T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||
});
|
||||
|
||||
it('sets the end date for a winter gala', () => {
|
||||
const date = new Date('2024-12-22');
|
||||
const matchers = getAllScheduleMatchingGroups(date);
|
||||
expect(matchers.seasonalGear.end).to.eql(moment.utc(`2025-03-21T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||
});
|
||||
|
||||
it('sets the end date in new year for a winter gala', () => {
|
||||
const date = new Date('2025-01-04');
|
||||
const matchers = getAllScheduleMatchingGroups(date);
|
||||
expect(matchers.seasonalGear.end).to.eql(moment.utc(`2025-03-21T${String(switchoverTime).padStart(2, '0')}:00:00.000Z`).toDate());
|
||||
});
|
||||
|
||||
it('uses correct date for first hours of the month', () => {
|
||||
// if the date is checked before CONTENT_SWITCHOVER_TIME_OFFSET,
|
||||
// it should be considered the previous month
|
||||
const date = new Date('2024-05-01T02:00:00.000Z');
|
||||
const matchers = getAllScheduleMatchingGroups(date);
|
||||
expect(matchers.petQuests.items).to.contain('snake');
|
||||
expect(matchers.petQuests.items).to.not.contain('horse');
|
||||
expect(matchers.timeTravelers.match('202304'), '202304').to.be.true;
|
||||
expect(matchers.timeTravelers.match('202404'), '202404').to.be.false;
|
||||
expect(matchers.timeTravelers.match('202305'), '202305').to.be.false;
|
||||
});
|
||||
|
||||
it('uses correct date after switchover time', () => {
|
||||
// if the date is checked after CONTENT_SWITCHOVER_TIME_OFFSET,
|
||||
// it should be considered the current
|
||||
const date = new Date('2024-05-01T09:00:00.000Z');
|
||||
const matchers = getAllScheduleMatchingGroups(date);
|
||||
expect(matchers.petQuests.items).to.contain('snake');
|
||||
expect(matchers.petQuests.items).to.not.contain('horse');
|
||||
expect(matchers.timeTravelers.match('202304'), '202304').to.be.false;
|
||||
expect(matchers.timeTravelers.match('202305'), '202305').to.be.true;
|
||||
expect(matchers.timeTravelers.match('202405'), '202405').to.be.false;
|
||||
});
|
||||
|
||||
it('uses UTC timezone', () => {
|
||||
// if the date is checked after CONTENT_SWITCHOVER_TIME_OFFSET,
|
||||
// it should be considered the current
|
||||
clock = sinon.useFakeTimers(new Date('2024-05-01T05:00:00.000-04:00'));
|
||||
const matchers = getAllScheduleMatchingGroups();
|
||||
expect(matchers.petQuests.items).to.contain('snake');
|
||||
expect(matchers.petQuests.items).to.not.contain('horse');
|
||||
expect(matchers.timeTravelers.match('202304'), '202304').to.be.false;
|
||||
expect(matchers.timeTravelers.match('202305'), '202305').to.be.true;
|
||||
expect(matchers.timeTravelers.match('202405'), '202405').to.be.false;
|
||||
});
|
||||
|
||||
it('contains content for repeating events', () => {
|
||||
const date = new Date('2024-04-15');
|
||||
const matchers = getAllScheduleMatchingGroups(date);
|
||||
expect(matchers.premiumHatchingPotions).to.exist;
|
||||
expect(matchers.premiumHatchingPotions.items.length).to.equal(4);
|
||||
expect(matchers.premiumHatchingPotions.items.indexOf('Garden')).to.not.equal(-1);
|
||||
expect(matchers.premiumHatchingPotions.items.length).to.equal(5);
|
||||
expect(matchers.premiumHatchingPotions.items.indexOf('Veggie')).to.not.equal(-1);
|
||||
expect(matchers.premiumHatchingPotions.items.indexOf('Porcelain')).to.not.equal(-1);
|
||||
});
|
||||
|
||||
@@ -167,6 +230,8 @@ describe('Content Schedule', () => {
|
||||
});
|
||||
|
||||
it('premium hatching potions', () => {
|
||||
const lastReleaseDate = maxBy(Object.values(HATCHING_POTIONS_RELEASE_DATES), value => new Date(`${value.year}-${value.month}-${value.day}`));
|
||||
clock = sinon.useFakeTimers(new Date(`${lastReleaseDate.year}-${lastReleaseDate.month}-${lastReleaseDate.day + 1}`));
|
||||
const potionKeys = Object.keys(potions.premium);
|
||||
Object.keys(MONTHLY_SCHEDULE).forEach(key => {
|
||||
const monthlyPotions = MONTHLY_SCHEDULE[key][21].find(item => item.type === 'premiumHatchingPotions');
|
||||
@@ -245,27 +310,33 @@ describe('Content Schedule', () => {
|
||||
it('allows sets matching the month', () => {
|
||||
const date = new Date('2024-07-08');
|
||||
const matcher = getAllScheduleMatchingGroups(date).timeTravelers;
|
||||
expect(matcher.match('202307')).to.be.true;
|
||||
expect(matcher.match('202207')).to.be.true;
|
||||
expect(matcher.match('202307'), '202307').to.be.true;
|
||||
expect(matcher.match('202207'), '202207').to.be.true;
|
||||
});
|
||||
|
||||
it('disallows sets not matching the month', () => {
|
||||
const date = new Date('2024-07-08');
|
||||
const matcher = getAllScheduleMatchingGroups(date).timeTravelers;
|
||||
expect(matcher.match('202306')).to.be.false;
|
||||
expect(matcher.match('202402')).to.be.false;
|
||||
expect(matcher.match('202306'), '202306').to.be.false;
|
||||
expect(matcher.match('202402'), '202402').to.be.false;
|
||||
});
|
||||
|
||||
it('disallows sets from current month', () => {
|
||||
const date = new Date('2024-07-08');
|
||||
const matcher = getAllScheduleMatchingGroups(date).timeTravelers;
|
||||
expect(matcher.match('202407')).to.be.false;
|
||||
expect(matcher.match('202407'), '202407').to.be.false;
|
||||
});
|
||||
|
||||
it('disallows sets from the future', () => {
|
||||
const date = new Date('2024-07-08');
|
||||
const matcher = getAllScheduleMatchingGroups(date).backgrounds;
|
||||
expect(matcher.match('202507')).to.be.false;
|
||||
const matcher = getAllScheduleMatchingGroups(date).timeTravelers;
|
||||
expect(matcher.match('202507'), '202507').to.be.false;
|
||||
});
|
||||
|
||||
it('matches sets released in the earlier half of the year', () => {
|
||||
const date = new Date('2024-07-08');
|
||||
const matcher = getAllScheduleMatchingGroups(date).timeTravelers;
|
||||
expect(matcher.match('202401'), '202401').to.be.true;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -45,7 +45,7 @@ describe('time-travelers store', () => {
|
||||
|
||||
describe('on may 1st', () => {
|
||||
beforeEach(() => {
|
||||
date = new Date('2024-05-01');
|
||||
date = new Date('2024-05-01T09:00:00.000Z');
|
||||
});
|
||||
it('returns the correct gear', () => {
|
||||
const items = timeTravelers.timeTravelerStore(user, date);
|
||||
|
||||
466
website/client/package-lock.json
generated
@@ -23,7 +23,6 @@
|
||||
"bootstrap": "^4.6.0",
|
||||
"bootstrap-vue": "^2.23.1",
|
||||
"core-js": "^3.33.1",
|
||||
"dompurify": "^3.0.3",
|
||||
"eslint": "7.32.0",
|
||||
"eslint-config-habitrpg": "6.2.0",
|
||||
"eslint-plugin-mocha": "5.3.0",
|
||||
@@ -39,7 +38,6 @@
|
||||
"sass": "^1.63.4",
|
||||
"sass-loader": "^14.1.1",
|
||||
"sinon": "^17.0.1",
|
||||
"smartbanner.js": "^1.19.3",
|
||||
"stopword": "^2.0.8",
|
||||
"timers-browserify": "^2.0.12",
|
||||
"uuid": "^9.0.1",
|
||||
@@ -59,7 +57,7 @@
|
||||
"chai": "^5.1.0",
|
||||
"inspectpack": "^4.7.1",
|
||||
"terser-webpack-plugin": "^5.3.10",
|
||||
"webpack": "^5.89.0"
|
||||
"webpack": "^5.94.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@aashutoshrathi/word-wrap": {
|
||||
@@ -2307,15 +2305,6 @@
|
||||
"@types/json-schema": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/eslint-scope": {
|
||||
"version": "3.7.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz",
|
||||
"integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==",
|
||||
"dependencies": {
|
||||
"@types/eslint": "*",
|
||||
"@types/estree": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
||||
@@ -3129,9 +3118,9 @@
|
||||
"integrity": "sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA=="
|
||||
},
|
||||
"node_modules/@webassemblyjs/ast": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz",
|
||||
"integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz",
|
||||
"integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/helper-numbers": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6"
|
||||
@@ -3148,9 +3137,9 @@
|
||||
"integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q=="
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-buffer": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz",
|
||||
"integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA=="
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz",
|
||||
"integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw=="
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-numbers": {
|
||||
"version": "1.11.6",
|
||||
@@ -3168,14 +3157,14 @@
|
||||
"integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA=="
|
||||
},
|
||||
"node_modules/@webassemblyjs/helper-wasm-section": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz",
|
||||
"integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz",
|
||||
"integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-buffer": "1.11.6",
|
||||
"@webassemblyjs/ast": "1.12.1",
|
||||
"@webassemblyjs/helper-buffer": "1.12.1",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/wasm-gen": "1.11.6"
|
||||
"@webassemblyjs/wasm-gen": "1.12.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/ieee754": {
|
||||
@@ -3200,26 +3189,26 @@
|
||||
"integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA=="
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-edit": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz",
|
||||
"integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz",
|
||||
"integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-buffer": "1.11.6",
|
||||
"@webassemblyjs/ast": "1.12.1",
|
||||
"@webassemblyjs/helper-buffer": "1.12.1",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-section": "1.11.6",
|
||||
"@webassemblyjs/wasm-gen": "1.11.6",
|
||||
"@webassemblyjs/wasm-opt": "1.11.6",
|
||||
"@webassemblyjs/wasm-parser": "1.11.6",
|
||||
"@webassemblyjs/wast-printer": "1.11.6"
|
||||
"@webassemblyjs/helper-wasm-section": "1.12.1",
|
||||
"@webassemblyjs/wasm-gen": "1.12.1",
|
||||
"@webassemblyjs/wasm-opt": "1.12.1",
|
||||
"@webassemblyjs/wasm-parser": "1.12.1",
|
||||
"@webassemblyjs/wast-printer": "1.12.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-gen": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz",
|
||||
"integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz",
|
||||
"integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/ast": "1.12.1",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/ieee754": "1.11.6",
|
||||
"@webassemblyjs/leb128": "1.11.6",
|
||||
@@ -3227,22 +3216,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-opt": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz",
|
||||
"integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz",
|
||||
"integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/helper-buffer": "1.11.6",
|
||||
"@webassemblyjs/wasm-gen": "1.11.6",
|
||||
"@webassemblyjs/wasm-parser": "1.11.6"
|
||||
"@webassemblyjs/ast": "1.12.1",
|
||||
"@webassemblyjs/helper-buffer": "1.12.1",
|
||||
"@webassemblyjs/wasm-gen": "1.12.1",
|
||||
"@webassemblyjs/wasm-parser": "1.12.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/wasm-parser": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz",
|
||||
"integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz",
|
||||
"integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/ast": "1.12.1",
|
||||
"@webassemblyjs/helper-api-error": "1.11.6",
|
||||
"@webassemblyjs/helper-wasm-bytecode": "1.11.6",
|
||||
"@webassemblyjs/ieee754": "1.11.6",
|
||||
@@ -3251,11 +3240,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@webassemblyjs/wast-printer": {
|
||||
"version": "1.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz",
|
||||
"integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==",
|
||||
"version": "1.12.1",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz",
|
||||
"integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==",
|
||||
"dependencies": {
|
||||
"@webassemblyjs/ast": "1.11.6",
|
||||
"@webassemblyjs/ast": "1.12.1",
|
||||
"@xtuc/long": "4.2.2"
|
||||
}
|
||||
},
|
||||
@@ -3326,10 +3315,10 @@
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn-import-assertions": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz",
|
||||
"integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==",
|
||||
"node_modules/acorn-import-attributes": {
|
||||
"version": "1.9.5",
|
||||
"resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz",
|
||||
"integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==",
|
||||
"peerDependencies": {
|
||||
"acorn": "^8"
|
||||
}
|
||||
@@ -3945,9 +3934,9 @@
|
||||
"integrity": "sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w=="
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.2",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
|
||||
"integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==",
|
||||
"version": "1.20.3",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
|
||||
"integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.5",
|
||||
@@ -3957,7 +3946,7 @@
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.11.0",
|
||||
"qs": "6.13.0",
|
||||
"raw-body": "2.5.2",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
@@ -4046,11 +4035,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/braces": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
|
||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||
"dependencies": {
|
||||
"fill-range": "^7.0.1"
|
||||
"fill-range": "^7.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
@@ -4151,6 +4140,33 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/call-bind-apply-helpers": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz",
|
||||
"integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/call-bound": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz",
|
||||
"integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
"get-intrinsic": "^1.2.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/callsites": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
|
||||
@@ -4627,9 +4643,9 @@
|
||||
"integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz",
|
||||
"integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==",
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
|
||||
"integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
@@ -5398,11 +5414,6 @@
|
||||
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/dompurify": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.6.tgz",
|
||||
"integrity": "sha512-ilkD8YEnnGh1zJ240uJsW7AzE+2qpbOUYjacomn3AvJ6J4JhKGSZ2nh4wUIXPZrEPppaCLx5jFe8T89Rk8tQ7w=="
|
||||
},
|
||||
"node_modules/domutils": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
|
||||
@@ -5438,6 +5449,19 @@
|
||||
"resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz",
|
||||
"integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA=="
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.0.tgz",
|
||||
"integrity": "sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.0",
|
||||
"es-errors": "^1.3.0",
|
||||
"gopd": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/duplexer": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
|
||||
@@ -5480,9 +5504,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
|
||||
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
@@ -5496,9 +5520,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.15.0",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz",
|
||||
"integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==",
|
||||
"version": "5.17.1",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz",
|
||||
"integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.4",
|
||||
"tapable": "^2.2.0"
|
||||
@@ -5604,12 +5628,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
|
||||
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.2.4"
|
||||
},
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
@@ -5627,6 +5648,17 @@
|
||||
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz",
|
||||
"integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w=="
|
||||
},
|
||||
"node_modules/es-object-atoms": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz",
|
||||
"integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-set-tostringtag": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz",
|
||||
@@ -6711,36 +6743,36 @@
|
||||
}
|
||||
},
|
||||
"node_modules/express": {
|
||||
"version": "4.19.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz",
|
||||
"integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==",
|
||||
"version": "4.21.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
|
||||
"integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
"body-parser": "1.20.2",
|
||||
"body-parser": "1.20.3",
|
||||
"content-disposition": "0.5.4",
|
||||
"content-type": "~1.0.4",
|
||||
"cookie": "0.6.0",
|
||||
"cookie": "0.7.1",
|
||||
"cookie-signature": "1.0.6",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"encodeurl": "~1.0.2",
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"finalhandler": "1.2.0",
|
||||
"finalhandler": "1.3.1",
|
||||
"fresh": "0.5.2",
|
||||
"http-errors": "2.0.0",
|
||||
"merge-descriptors": "1.0.1",
|
||||
"merge-descriptors": "1.0.3",
|
||||
"methods": "~1.1.2",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
"path-to-regexp": "0.1.7",
|
||||
"path-to-regexp": "0.1.12",
|
||||
"proxy-addr": "~2.0.7",
|
||||
"qs": "6.11.0",
|
||||
"qs": "6.13.0",
|
||||
"range-parser": "~1.2.1",
|
||||
"safe-buffer": "5.2.1",
|
||||
"send": "0.18.0",
|
||||
"serve-static": "1.15.0",
|
||||
"send": "0.19.0",
|
||||
"serve-static": "1.16.2",
|
||||
"setprototypeof": "1.2.0",
|
||||
"statuses": "2.0.1",
|
||||
"type-is": "~1.6.18",
|
||||
@@ -6749,6 +6781,10 @@
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/express"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/array-flatten": {
|
||||
@@ -6871,9 +6907,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
},
|
||||
@@ -6893,12 +6929,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/finalhandler": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
|
||||
"integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
|
||||
"version": "1.3.1",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
|
||||
"integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
|
||||
"dependencies": {
|
||||
"debug": "2.6.9",
|
||||
"encodeurl": "~1.0.2",
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
@@ -7141,15 +7177,20 @@
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
|
||||
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.6.tgz",
|
||||
"integrity": "sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
"dunder-proto": "^1.0.0",
|
||||
"es-define-property": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.0.0",
|
||||
"function-bind": "^1.1.2",
|
||||
"has-proto": "^1.0.1",
|
||||
"has-symbols": "^1.0.3",
|
||||
"hasown": "^2.0.0"
|
||||
"gopd": "^1.2.0",
|
||||
"has-symbols": "^1.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"math-intrinsics": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
@@ -7269,11 +7310,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
|
||||
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.1.3"
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
@@ -7369,9 +7410,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/has-symbols": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
|
||||
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
@@ -7399,9 +7440,9 @@
|
||||
"integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg=="
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz",
|
||||
"integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
@@ -8935,6 +8976,14 @@
|
||||
"markdown-it": "bin/markdown-it.js"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.0.0.tgz",
|
||||
"integrity": "sha512-4MqMiKP90ybymYvsut0CH2g4XWbfLtmlCkXmtmdcDCxNB+mQcu1w/1+L/VD7vi/PSv7X2JYV7SCcR+jiPXnQtA==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/mdn-data": {
|
||||
"version": "2.0.14",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
|
||||
@@ -8974,9 +9023,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/merge-descriptors": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
||||
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
|
||||
"integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/merge-source-map": {
|
||||
"version": "1.1.0",
|
||||
@@ -9008,11 +9060,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/micromatch": {
|
||||
"version": "4.0.5",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
|
||||
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
||||
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
||||
"dependencies": {
|
||||
"braces": "^3.0.2",
|
||||
"braces": "^3.0.3",
|
||||
"picomatch": "^2.3.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -9878,9 +9930,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/object-inspect": {
|
||||
"version": "1.13.1",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
|
||||
"integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
|
||||
"version": "1.13.3",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz",
|
||||
"integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
@@ -10326,9 +10381,9 @@
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
|
||||
},
|
||||
"node_modules/path-to-regexp": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
|
||||
"version": "0.1.12",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
|
||||
"integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="
|
||||
},
|
||||
"node_modules/path-type": {
|
||||
"version": "4.0.0",
|
||||
@@ -11145,11 +11200,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
|
||||
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
|
||||
"version": "6.13.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
|
||||
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.0.4"
|
||||
"side-channel": "^1.0.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
@@ -11752,9 +11807,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/send": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
|
||||
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
|
||||
"version": "0.19.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
|
||||
"integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
|
||||
"dependencies": {
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
@@ -11787,6 +11842,14 @@
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"node_modules/send/node_modules/encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/send/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
@@ -11871,14 +11934,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/serve-static": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
|
||||
"integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
|
||||
"version": "1.16.2",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
|
||||
"integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
|
||||
"dependencies": {
|
||||
"encodeurl": "~1.0.2",
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"parseurl": "~1.3.3",
|
||||
"send": "0.18.0"
|
||||
"send": "0.19.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
@@ -11967,13 +12030,68 @@
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
|
||||
"integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
|
||||
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.0",
|
||||
"get-intrinsic": "^1.0.2",
|
||||
"object-inspect": "^1.9.0"
|
||||
"es-errors": "^1.3.0",
|
||||
"object-inspect": "^1.13.3",
|
||||
"side-channel-list": "^1.0.0",
|
||||
"side-channel-map": "^1.0.1",
|
||||
"side-channel-weakmap": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel-list": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
|
||||
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"object-inspect": "^1.13.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel-map": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
|
||||
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.5",
|
||||
"object-inspect": "^1.13.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel-weakmap": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
|
||||
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.5",
|
||||
"object-inspect": "^1.13.3",
|
||||
"side-channel-map": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
@@ -12095,17 +12213,6 @@
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"node_modules/smartbanner.js": {
|
||||
"version": "1.22.0",
|
||||
"resolved": "https://registry.npmjs.org/smartbanner.js/-/smartbanner.js-1.22.0.tgz",
|
||||
"integrity": "sha512-JhERLgwEPuzVdwAHds1J6txWBVq9BwmlAn+5VicrAfIOMO3ehNA7VHu8IIJNnW1LsElSCaLWxjdLjlEwLDqAvA==",
|
||||
"engines": {
|
||||
"node": ">=10.24.1 <22.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ain"
|
||||
}
|
||||
},
|
||||
"node_modules/sockjs": {
|
||||
"version": "0.3.24",
|
||||
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
|
||||
@@ -13342,9 +13449,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
|
||||
"integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz",
|
||||
"integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==",
|
||||
"dependencies": {
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
"graceful-fs": "^4.1.2"
|
||||
@@ -13378,33 +13485,32 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.89.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz",
|
||||
"integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==",
|
||||
"version": "5.94.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz",
|
||||
"integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==",
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
"@types/estree": "^1.0.0",
|
||||
"@webassemblyjs/ast": "^1.11.5",
|
||||
"@webassemblyjs/wasm-edit": "^1.11.5",
|
||||
"@webassemblyjs/wasm-parser": "^1.11.5",
|
||||
"@types/estree": "^1.0.5",
|
||||
"@webassemblyjs/ast": "^1.12.1",
|
||||
"@webassemblyjs/wasm-edit": "^1.12.1",
|
||||
"@webassemblyjs/wasm-parser": "^1.12.1",
|
||||
"acorn": "^8.7.1",
|
||||
"acorn-import-assertions": "^1.9.0",
|
||||
"browserslist": "^4.14.5",
|
||||
"acorn-import-attributes": "^1.9.5",
|
||||
"browserslist": "^4.21.10",
|
||||
"chrome-trace-event": "^1.0.2",
|
||||
"enhanced-resolve": "^5.15.0",
|
||||
"enhanced-resolve": "^5.17.1",
|
||||
"es-module-lexer": "^1.2.1",
|
||||
"eslint-scope": "5.1.1",
|
||||
"events": "^3.2.0",
|
||||
"glob-to-regexp": "^0.4.1",
|
||||
"graceful-fs": "^4.2.9",
|
||||
"graceful-fs": "^4.2.11",
|
||||
"json-parse-even-better-errors": "^2.3.1",
|
||||
"loader-runner": "^4.2.0",
|
||||
"mime-types": "^2.1.27",
|
||||
"neo-async": "^2.6.2",
|
||||
"schema-utils": "^3.2.0",
|
||||
"tapable": "^2.1.1",
|
||||
"terser-webpack-plugin": "^5.3.7",
|
||||
"watchpack": "^2.4.0",
|
||||
"terser-webpack-plugin": "^5.3.10",
|
||||
"watchpack": "^2.4.1",
|
||||
"webpack-sources": "^3.2.3"
|
||||
},
|
||||
"bin": {
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
"bootstrap": "^4.6.0",
|
||||
"bootstrap-vue": "^2.23.1",
|
||||
"core-js": "^3.33.1",
|
||||
"dompurify": "^3.0.3",
|
||||
"eslint": "7.32.0",
|
||||
"eslint-config-habitrpg": "6.2.0",
|
||||
"eslint-plugin-mocha": "5.3.0",
|
||||
@@ -41,7 +40,6 @@
|
||||
"sass": "^1.63.4",
|
||||
"sass-loader": "^14.1.1",
|
||||
"sinon": "^17.0.1",
|
||||
"smartbanner.js": "^1.19.3",
|
||||
"stopword": "^2.0.8",
|
||||
"timers-browserify": "^2.0.12",
|
||||
"uuid": "^9.0.1",
|
||||
@@ -61,6 +59,6 @@
|
||||
"chai": "^5.1.0",
|
||||
"inspectpack": "^4.7.1",
|
||||
"terser-webpack-plugin": "^5.3.10",
|
||||
"webpack": "^5.89.0"
|
||||
"webpack": "^5.94.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,18 +7,6 @@
|
||||
<title>Habitica - Gamify Your Life</title>
|
||||
<meta name="description" content="Habitica is a free habit and productivity app that treats your real life like a game. Habitica can help you achieve your goals to become healthy and happy.">
|
||||
<meta name="keywords" content="Habits,Goals,Todo,Gamification,Health,Fitness,School,Work">
|
||||
<meta name="smartbanner:title" content="Habitica">
|
||||
<meta name="smartbanner:author" content="HabitRPG, Inc.">
|
||||
<meta name="smartbanner:price" content="FREE">
|
||||
<meta name="smartbanner:price-suffix-apple" content=" - On the App Store">
|
||||
<meta name="smartbanner:price-suffix-google" content=" - In Google Play">
|
||||
<meta name="smartbanner:icon-apple" content="/static/presskit/Logo/iOS.png">
|
||||
<meta name="smartbanner:icon-google" content="/static/presskit/Logo/Android.png">
|
||||
<meta name="smartbanner:button" content="VIEW">
|
||||
<meta name="smartbanner:button-url-apple" content="https://itunes.apple.com/us/app/habitica-gamified-taskmanager/id994882113">
|
||||
<meta name="smartbanner:button-url-google" content="https://play.google.com/store/apps/details?id=com.habitrpg.android.habitica">
|
||||
<meta name="smartbanner:enabled-platforms" content="android,ios">
|
||||
<meta name="smartbanner:hide-ttl" content="2592000000">
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto+Condensed:400,400i,700,700i|Roboto:400,400i,700,700i" rel="stylesheet">
|
||||
<link rel="shortcut icon" sizes="48x48" href="/static/icons/favicon.ico">
|
||||
<link rel="shortcut icon" sizes="192x192" href="/static/icons/favicon_192x192.png">
|
||||
|
||||
|
After Width: | Height: | Size: 3.9 KiB |
BIN
website/client/public/static/npc/birthday/customizations_npc.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
BIN
website/client/public/static/npc/fall/customizations_npc.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
BIN
website/client/public/static/npc/nye/customizations_npc.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
BIN
website/client/public/static/npc/spring/customizations_npc.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
BIN
website/client/public/static/npc/summer/customizations_npc.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
BIN
website/client/public/static/npc/winter/customizations_npc.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
@@ -27,73 +27,15 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
id="app"
|
||||
:class="{
|
||||
'casting-spell': castingSpell,
|
||||
}"
|
||||
>
|
||||
<!-- <banned-account-modal /> -->
|
||||
<amazon-payments-modal v-if="!isStaticPage" />
|
||||
<payments-success-modal />
|
||||
<sub-cancel-modal-confirm v-if="isUserLoaded" />
|
||||
<sub-canceled-modal v-if="isUserLoaded" />
|
||||
<bug-report-modal v-if="isUserLoaded" />
|
||||
<bug-report-success-modal v-if="isUserLoaded" />
|
||||
<external-link-modal />
|
||||
<birthday-modal />
|
||||
<snackbars />
|
||||
<router-view v-if="!isUserLoggedIn || isStaticPage" />
|
||||
<template v-else>
|
||||
<template v-if="isUserLoaded">
|
||||
<chat-banner />
|
||||
<damage-paused-banner />
|
||||
<gems-promo-banner />
|
||||
<gift-promo-banner />
|
||||
<birthday-banner />
|
||||
<notifications-display />
|
||||
<app-menu />
|
||||
<div
|
||||
class="container-fluid"
|
||||
:class="{'no-margin': noMargin}"
|
||||
>
|
||||
<app-header />
|
||||
<buyModal
|
||||
:item="selectedItemToBuy || {}"
|
||||
:with-pin="true"
|
||||
:generic-purchase="genericPurchase(selectedItemToBuy)"
|
||||
@buyPressed="customPurchase($event)"
|
||||
/>
|
||||
<selectMembersModal
|
||||
:item="selectedSpellToBuy || {}"
|
||||
:group="user.party"
|
||||
@memberSelected="memberSelected($event)"
|
||||
/>
|
||||
<div :class="{sticky: user.preferences.stickyHeader}">
|
||||
<router-view />
|
||||
</div>
|
||||
</div>
|
||||
<app-footer v-if="!hideFooter" />
|
||||
<audio
|
||||
id="sound"
|
||||
ref="sound"
|
||||
autoplay="autoplay"
|
||||
></audio>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
<snackbars />
|
||||
<router-view v-if="!isUserLoggedIn || isStaticPage" />
|
||||
<user-main v-else />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
#app {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
#loading-screen-inapp {
|
||||
#melior {
|
||||
color: $white;
|
||||
@@ -163,68 +105,20 @@
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import { loadProgressBar } from 'axios-progress-bar';
|
||||
|
||||
import birthdayModal from '@/components/news/birthdayModal';
|
||||
import AppMenu from './components/header/menu';
|
||||
import AppHeader from './components/header/index';
|
||||
import ChatBanner from './components/header/banners/chatBanner';
|
||||
import DamagePausedBanner from './components/header/banners/damagePaused';
|
||||
import GemsPromoBanner from './components/header/banners/gemsPromo';
|
||||
import GiftPromoBanner from './components/header/banners/giftPromo';
|
||||
import BirthdayBanner from './components/header/banners/birthdayBanner';
|
||||
import AppFooter from './components/appFooter';
|
||||
import notificationsDisplay from './components/notifications';
|
||||
import snackbars from './components/snackbars/notifications';
|
||||
import { mapState } from '@/libs/store';
|
||||
import * as Analytics from '@/libs/analytics';
|
||||
import BuyModal from './components/shops/buyModal.vue';
|
||||
import SelectMembersModal from '@/components/selectMembersModal.vue';
|
||||
import notifications from '@/mixins/notifications';
|
||||
import { setup as setupPayments } from '@/libs/payments';
|
||||
import amazonPaymentsModal from '@/components/payments/amazonModal';
|
||||
import paymentsSuccessModal from '@/components/payments/successModal';
|
||||
import subCancelModalConfirm from '@/components/payments/cancelModalConfirm';
|
||||
import subCanceledModal from '@/components/payments/canceledModal';
|
||||
import externalLinkModal from '@/components/externalLinkModal.vue';
|
||||
|
||||
import spellsMixin from '@/mixins/spells';
|
||||
import {
|
||||
CONSTANTS,
|
||||
getLocalSetting,
|
||||
removeLocalSetting,
|
||||
} from '@/libs/userlocalManager';
|
||||
|
||||
const bugReportModal = () => import(/* webpackChunkName: "bug-report-modal" */'@/components/bugReportModal');
|
||||
const bugReportSuccessModal = () => import(/* webpackChunkName: "bug-report-success-modal" */'@/components/bugReportSuccessModal');
|
||||
import { mapState } from '@/libs/store';
|
||||
import userMain from '@/pages/user-main';
|
||||
import snackbars from '@/components/snackbars/notifications';
|
||||
|
||||
const COMMUNITY_MANAGER_EMAIL = process.env.EMAILS_COMMUNITY_MANAGER_EMAIL; // eslint-disable-line
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
AppMenu,
|
||||
AppHeader,
|
||||
AppFooter,
|
||||
birthdayModal,
|
||||
ChatBanner,
|
||||
DamagePausedBanner,
|
||||
GemsPromoBanner,
|
||||
GiftPromoBanner,
|
||||
BirthdayBanner,
|
||||
notificationsDisplay,
|
||||
snackbars,
|
||||
BuyModal,
|
||||
SelectMembersModal,
|
||||
amazonPaymentsModal,
|
||||
paymentsSuccessModal,
|
||||
subCancelModalConfirm,
|
||||
subCanceledModal,
|
||||
bugReportModal,
|
||||
bugReportSuccessModal,
|
||||
externalLinkModal,
|
||||
userMain,
|
||||
},
|
||||
mixins: [notifications, spellsMixin],
|
||||
data () {
|
||||
return {
|
||||
selectedItemToBuy: null,
|
||||
@@ -238,71 +132,25 @@ export default {
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(['isUserLoggedIn', 'browserTimezoneUtcOffset', 'isUserLoaded', 'notificationsRemoved']),
|
||||
...mapState(['isUserLoggedIn', 'isUserLoaded', 'notificationsRemoved']),
|
||||
...mapState({ user: 'user.data' }),
|
||||
isStaticPage () {
|
||||
return this.$route.meta.requiresLogin === false;
|
||||
},
|
||||
castingSpell () {
|
||||
return this.$store.state.spellOptions.castingSpell;
|
||||
},
|
||||
noMargin () {
|
||||
return ['privateMessages'].includes(this.$route.name);
|
||||
},
|
||||
hideFooter () {
|
||||
return ['privateMessages'].includes(this.$route.name);
|
||||
},
|
||||
},
|
||||
created () {
|
||||
this.$root.$on('playSound', sound => {
|
||||
const theme = this.user.preferences.sound;
|
||||
|
||||
if (!theme || theme === 'off') {
|
||||
return;
|
||||
}
|
||||
|
||||
const file = `/static/audio/${theme}/${sound}`;
|
||||
|
||||
if (this.audioSuffix === null) {
|
||||
this.audioSource = document.createElement('source');
|
||||
if (this.$refs.sound.canPlayType('audio/ogg')) {
|
||||
this.audioSuffix = '.ogg';
|
||||
this.audioSource.type = 'audio/ogg';
|
||||
} else {
|
||||
this.audioSuffix = '.mp3';
|
||||
this.audioSource.type = 'audio/mp3';
|
||||
}
|
||||
this.audioSource.src = file + this.audioSuffix;
|
||||
this.$refs.sound.appendChild(this.audioSource);
|
||||
} else {
|
||||
this.audioSource.src = file + this.audioSuffix;
|
||||
}
|
||||
|
||||
this.$refs.sound.load();
|
||||
// Setup listener for title
|
||||
this.$store.watch(state => state.title, title => {
|
||||
document.title = title;
|
||||
});
|
||||
|
||||
// @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.selectedItemToBuy = item;
|
||||
this.$root.$emit('bv::show::modal', 'buy-modal');
|
||||
});
|
||||
|
||||
this.$root.$on('bv::modal::hidden', event => {
|
||||
if (event.componentId === 'buy-modal') {
|
||||
this.$root.$emit('buyModal::hidden', this.selectedItemToBuy.key);
|
||||
this.$store.watch(state => state.isUserLoaded, () => {
|
||||
if (this.isUserLoaded) {
|
||||
this.hideLoadingScreen();
|
||||
}
|
||||
});
|
||||
|
||||
this.$root.$on('selectMembersModal::showItem', item => {
|
||||
this.selectedSpellToBuy = item;
|
||||
this.$root.$emit('bv::show::modal', 'select-member-modal');
|
||||
});
|
||||
|
||||
// @TODO split up this file, it's too big
|
||||
|
||||
loadProgressBar({
|
||||
showSpinner: false,
|
||||
this.$nextTick(() => {
|
||||
// Load external scripts after the app has been rendered
|
||||
Analytics.load();
|
||||
});
|
||||
|
||||
axios.interceptors.response.use(response => { // Set up Response interceptors
|
||||
@@ -414,79 +262,20 @@ export default {
|
||||
|
||||
return Promise.reject(error);
|
||||
});
|
||||
|
||||
// Setup listener for title
|
||||
this.$store.watch(state => state.title, title => {
|
||||
document.title = title;
|
||||
});
|
||||
this.$nextTick(() => {
|
||||
// Load external scripts after the app has been rendered
|
||||
Analytics.load();
|
||||
});
|
||||
|
||||
if (this.isUserLoggedIn && !this.isStaticPage) {
|
||||
// Load the user and the user tasks
|
||||
Promise.all([
|
||||
this.$store.dispatch('user:fetch'),
|
||||
this.$store.dispatch('tasks:fetchUserTasks'),
|
||||
]).then(() => {
|
||||
this.$store.state.isUserLoaded = true;
|
||||
Analytics.setUser();
|
||||
Analytics.updateUser();
|
||||
return axios.get(
|
||||
'/api/v4/i18n/browser-script',
|
||||
{
|
||||
language: this.user.preferences.language,
|
||||
headers: {
|
||||
'Cache-Control': 'no-cache',
|
||||
Pragma: 'no-cache',
|
||||
Expires: '0',
|
||||
},
|
||||
},
|
||||
);
|
||||
}).then(() => {
|
||||
const i18nData = window && window['habitica-i18n'];
|
||||
this.$loadLocale(i18nData);
|
||||
this.hideLoadingScreen();
|
||||
|
||||
// Adjust the timezone offset
|
||||
const browserTimezoneOffset = -this.browserTimezoneUtcOffset;
|
||||
if (this.user.preferences.timezoneOffset !== browserTimezoneOffset) {
|
||||
this.$store.dispatch('user:set', {
|
||||
'preferences.timezoneOffset': browserTimezoneOffset,
|
||||
});
|
||||
}
|
||||
|
||||
let appState = getLocalSetting(CONSTANTS.savedAppStateValues.SAVED_APP_STATE);
|
||||
if (appState) {
|
||||
appState = JSON.parse(appState);
|
||||
if (appState.paymentCompleted) {
|
||||
removeLocalSetting(CONSTANTS.savedAppStateValues.SAVED_APP_STATE);
|
||||
this.$root.$emit('habitica:payment-success', appState);
|
||||
}
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
// Load external scripts after the app has been rendered
|
||||
setupPayments();
|
||||
});
|
||||
}).catch(err => {
|
||||
console.error('Impossible to fetch user. Clean up localStorage and refresh.', err); // eslint-disable-line no-console
|
||||
});
|
||||
} else {
|
||||
this.hideLoadingScreen();
|
||||
}
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.$root.$off('playSound');
|
||||
this.$root.$off('buyModal::showItem');
|
||||
this.$root.$off('selectMembersModal::showItem');
|
||||
},
|
||||
mounted () {
|
||||
// Remove the index.html loading screen and now show the inapp loading
|
||||
const loadingScreen = document.getElementById('loading-screen');
|
||||
if (loadingScreen) document.body.removeChild(loadingScreen);
|
||||
|
||||
if (this.isStaticPage || !this.isUserLoggedIn) {
|
||||
this.hideLoadingScreen();
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
hideLoadingScreen () {
|
||||
this.loading = false;
|
||||
},
|
||||
checkForBannedUser (error) {
|
||||
const AUTH_SETTINGS = localStorage.getItem('habit-mobile-settings');
|
||||
const parseSettings = JSON.parse(AUTH_SETTINGS);
|
||||
@@ -507,57 +296,9 @@ export default {
|
||||
this.$store.dispatch('auth:logout', { redirectToLogin: true });
|
||||
return true;
|
||||
},
|
||||
itemSelected (item) {
|
||||
this.selectedItemToBuy = item;
|
||||
},
|
||||
genericPurchase (item) {
|
||||
if (!item) return false;
|
||||
|
||||
if (['card', 'debuffPotion'].includes(item.purchaseType)) return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
customPurchase (item) {
|
||||
if (item.purchaseType === 'card') {
|
||||
this.selectedSpellToBuy = item;
|
||||
|
||||
// hide the dialog
|
||||
this.$root.$emit('bv::hide::modal', 'buy-modal');
|
||||
// remove the dialog from our modal-stack,
|
||||
// the default hidden event is delayed
|
||||
this.$root.$emit('bv::modal::hidden', {
|
||||
target: {
|
||||
id: 'buy-modal',
|
||||
},
|
||||
});
|
||||
|
||||
this.$root.$emit('bv::show::modal', 'select-member-modal');
|
||||
}
|
||||
|
||||
if (item.purchaseType === 'debuffPotion') {
|
||||
this.castStart(item, this.user);
|
||||
}
|
||||
},
|
||||
async memberSelected (member) {
|
||||
await this.castStart(this.selectedSpellToBuy, member);
|
||||
|
||||
this.selectedSpellToBuy = null;
|
||||
|
||||
if (this.user.party._id) {
|
||||
this.$store.dispatch('party:getMembers', { forceLoad: true });
|
||||
}
|
||||
|
||||
this.$root.$emit('bv::hide::modal', 'select-member-modal');
|
||||
},
|
||||
hideLoadingScreen () {
|
||||
this.loading = false;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style src="intro.js/minified/introjs.min.css"></style>
|
||||
<style src="axios-progress-bar/dist/nprogress.css"></style>
|
||||
<style src="@/assets/scss/index.scss" lang="scss"></style>
|
||||
<style src="@/assets/scss/sprites.scss" lang="scss"></style>
|
||||
<style src="smartbanner.js/dist/smartbanner.min.css"></style>
|
||||
|
||||
|
Before Width: | Height: | Size: 8.1 KiB |
BIN
website/client/src/assets/images/confetti.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
website/client/src/assets/images/group-plans-static/group-management@3x.png
Executable file → Normal file
|
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 26 KiB |
BIN
website/client/src/assets/images/group-plans-static/team-based@3x.png
Executable file → Normal file
|
Before Width: | Height: | Size: 110 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 126 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 410 B |
|
Before Width: | Height: | Size: 5.0 KiB |
@@ -3,9 +3,9 @@
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
line-height: 1.71;
|
||||
border: 1px solid transparent;
|
||||
padding: 4px 12px;
|
||||
line-height: 1.714;
|
||||
border: 2px solid transparent;
|
||||
padding: 2px 12px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 3px 0 rgba($black, 0.12), 0 1px 2px 0 rgba($black, 0.24);
|
||||
color: $white;
|
||||
@@ -19,7 +19,7 @@
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border-color: $purple-400;
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
}
|
||||
|
||||
&:active, &.active:not(.btn-flat) {
|
||||
@@ -30,9 +30,9 @@
|
||||
cursor: default;
|
||||
color: $gray-50;
|
||||
opacity: 0.75;
|
||||
box-shadow: 0 1px 3px 0 rgba(26, 24, 29, 0.12), 0 1px 2px 0 rgba(26, 24, 29, 0.24);
|
||||
box-shadow: none;
|
||||
background-color: $gray-700;
|
||||
border: 1px solid transparent;
|
||||
border: 2px solid transparent;
|
||||
|
||||
.svg {
|
||||
color: $gray-300;
|
||||
@@ -40,7 +40,7 @@
|
||||
}
|
||||
|
||||
&.with-icon {
|
||||
height: 2rem; // otherwise would something set the height to 33px
|
||||
height: 32px; // otherwise would something set the height to 33px
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
@@ -48,40 +48,47 @@
|
||||
}
|
||||
|
||||
.btn-front {
|
||||
border: none !important;
|
||||
font-size: 16px;
|
||||
line-height: 1.5;
|
||||
padding: 7.5px 15.5px;
|
||||
padding: 2px 17px;
|
||||
|
||||
&:hover {
|
||||
border: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: $purple-200;
|
||||
border: 1px solid transparent;
|
||||
border: 2px solid transparent;
|
||||
line-height: 1.714;
|
||||
--icon-color: #{$purple-500};
|
||||
|
||||
&:focus {
|
||||
background: $purple-200;
|
||||
border-color: $purple-400;
|
||||
border: 2px solid $purple-400;
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
--icon-color: #{$white};
|
||||
}
|
||||
|
||||
&:not(:disabled):not(.disabled) {
|
||||
&:hover {
|
||||
background: #5d3b9c;
|
||||
border: 1px solid transparent;
|
||||
background: $purple-200;
|
||||
border: 2px solid transparent;
|
||||
|
||||
--icon-color: #{$white};
|
||||
}
|
||||
|
||||
&:active, &.active {
|
||||
background: $purple-200;
|
||||
border: 1px solid transparent;
|
||||
border: 2px solid transparent;
|
||||
box-shadow: none;
|
||||
|
||||
--icon-color: #{$white};
|
||||
}
|
||||
|
||||
&:active:focus, &.active:focus {
|
||||
box-shadow: none;
|
||||
border-color: $purple-400;
|
||||
border: 2px solid $purple-400;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,39 +104,43 @@
|
||||
.show > .btn-secondary.dropdown-toggle:not(.btn-success)
|
||||
{
|
||||
background: $white;
|
||||
border: 1px solid transparent;
|
||||
border: 2px solid transparent;
|
||||
color: $gray-50;
|
||||
|
||||
--icon-color: #{$gray-200};
|
||||
|
||||
&:focus, &:active {
|
||||
color: $gray-50;
|
||||
background: $white;
|
||||
border-color: $purple-400;
|
||||
border: 2px solid $purple-400;
|
||||
color: $gray-50;
|
||||
|
||||
--icon-color: #{$purple-300};
|
||||
}
|
||||
|
||||
&:not(:disabled):not(.disabled) {
|
||||
&:active, &.active {
|
||||
background: $white;
|
||||
border: 2px solid $purple-400;
|
||||
color: $purple-300;
|
||||
--icon-color: #{$purple-300};
|
||||
|
||||
&:focus {
|
||||
color: $purple-300;
|
||||
box-shadow: none;
|
||||
border-color: $purple-400;
|
||||
border: 2px solid $purple-400;
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
}
|
||||
|
||||
&:active {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
background: $white;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: $purple-300;
|
||||
|
||||
background: $white !important;
|
||||
border: 1px solid transparent;
|
||||
border: 2px solid transparent;
|
||||
|
||||
--icon-color: #{$purple-300};
|
||||
.svg {
|
||||
@@ -151,67 +162,116 @@
|
||||
|
||||
.btn-danger {
|
||||
background: $maroon-100;
|
||||
border: 1px solid transparent;
|
||||
border: 2px solid transparent;
|
||||
box-shadow: 0 1px 3px 0 rgba($black, 0.16), 0 1px 3px 0 rgba($black, 0.24);
|
||||
|
||||
|
||||
&:hover:not(:disabled):not(.disabled) {
|
||||
background: #e14e4e;
|
||||
border: 1px solid transparent;
|
||||
background: $maroon-100;
|
||||
border: 2px solid transparent;
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background: $maroon-100;
|
||||
border-color: $purple-400;
|
||||
border: 2px solid $purple-400;
|
||||
}
|
||||
|
||||
&:not(:disabled):not(.disabled):active:focus, &:not(:disabled):not(.disabled).active:focus {
|
||||
box-shadow: none;
|
||||
border-color: $purple-400;
|
||||
border: 2px solid $purple-400;
|
||||
}
|
||||
|
||||
&:not(:disabled):not(.disabled):active, &:not(:disabled):not(.disabled).active {
|
||||
background: $maroon-100;
|
||||
border: 1px solid transparent;
|
||||
border: 2px solid $purple-400;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-warning {
|
||||
background: $orange-10;
|
||||
box-shadow: 0 1px 3px 0 rgba($black, 0.16), 0 1px 3px 0 rgba($black, 0.24);
|
||||
color: $white !important;
|
||||
|
||||
&:hover:not(:disabled):not(.disabled) {
|
||||
background: $orange-10;
|
||||
color: $white;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background: $orange-10;
|
||||
border: 2px solid $purple-400;
|
||||
}
|
||||
|
||||
&:not(:disabled):not(.disabled):active:focus, &:not(:disabled):not(.disabled).active:focus {
|
||||
border: 2px solid $purple-400;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&:not(:disabled):not(.disabled):active, &:not(:disabled):not(.disabled).active {
|
||||
background: $orange-10;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
background: $green-50;
|
||||
border: 1px solid transparent;
|
||||
border: 2px solid transparent;
|
||||
|
||||
&:hover:not(:disabled):not(.disabled) {
|
||||
background: #32bd8a;
|
||||
border: 1px solid transparent;
|
||||
background: $green-50;
|
||||
border: 2px solid transparent;
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background: $green-50;
|
||||
border-color: $purple-400;
|
||||
border: 2px solid $purple-400;
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
}
|
||||
|
||||
&:not(:disabled):not(.disabled):active:focus, &:not(:disabled):not(.disabled).active:focus {
|
||||
border: 2px solid $purple-400;
|
||||
box-shadow: none;
|
||||
border-color: $purple-400;
|
||||
}
|
||||
|
||||
&:not(:disabled):not(.disabled):active, &:not(:disabled):not(.disabled).active {
|
||||
background: $green-50;
|
||||
border: 1px solid transparent;
|
||||
border: 2px solid $purple-400;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-info {
|
||||
background: $blue-50;
|
||||
border: 2px solid transparent;
|
||||
box-shadow: 0 1px 3px 0 rgba($black, 0.16), 0 1px 3px 0 rgba($black, 0.24);
|
||||
|
||||
&:disabled {
|
||||
background: $blue-50;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border: 2px solid transparent;
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
background: $blue-100;
|
||||
border: 2px solid $purple-400;
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
}
|
||||
|
||||
&:hover:not(:disabled):not(.disabled) {
|
||||
background-color: $blue-100;
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
}
|
||||
|
||||
&:active:not(:disabled):not(.disabled), &.active:not(:disabled):not(.disabled) {
|
||||
background: $blue-50;
|
||||
background: $blue-100;
|
||||
border: 2px solid $purple-400;
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,7 +280,7 @@
|
||||
width: 100%;
|
||||
padding: 8px;
|
||||
font-size: 14px;
|
||||
line-height: 1.43;
|
||||
line-height: 1.714;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
background: $gray-500;
|
||||
@@ -244,6 +304,6 @@
|
||||
|
||||
.btn-small {
|
||||
font-size: 12px;
|
||||
line-height: 1.33;
|
||||
padding: 4px 8px;
|
||||
line-height: 2;
|
||||
padding: 2px 2px;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
.dropdown > .btn {
|
||||
padding: 0.219rem 0.75rem;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
line-height: 1.714;
|
||||
padding: 2px 12px;
|
||||
}
|
||||
|
||||
.dropdown-toggle:hover {
|
||||
@@ -33,10 +34,10 @@
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
padding: 0px;
|
||||
border: none;
|
||||
border: transparent;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 3px 6px 0 rgba(26, 24, 29, 0.16), 0 3px 6px 0 rgba(26, 24, 29, 0.24);
|
||||
box-shadow: 0 3px 6px 0 rgba($black, 0.16), 0 3px 6px 0 rgba($black, 0.24);
|
||||
padding: 0;
|
||||
|
||||
}
|
||||
|
||||
@@ -113,6 +114,10 @@
|
||||
}
|
||||
|
||||
.dropdown-icon-item {
|
||||
line-height: 1;
|
||||
padding-top: 2px !important;
|
||||
padding-bottom: 2px !important;
|
||||
|
||||
.svg-icon {
|
||||
margin: 0px 16px 0px 0px;
|
||||
vertical-align: middle;
|
||||
@@ -128,7 +133,6 @@
|
||||
|
||||
.dropdown-toggle {
|
||||
width: 100% !important;
|
||||
height: 32px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,10 @@ ul {
|
||||
color: $purple-200;
|
||||
}
|
||||
|
||||
h4 {
|
||||
color: $gray-50;
|
||||
}
|
||||
|
||||
.body-text {
|
||||
font-size: 1em;
|
||||
color: $gray-10;
|
||||
|
||||
@@ -86,3 +86,91 @@ h4 {
|
||||
.opacity-75 {
|
||||
opacity: 0.75;
|
||||
}
|
||||
|
||||
.bg-gray-100 {
|
||||
background-color: $gray-100 !important;
|
||||
}
|
||||
|
||||
.bg-gray-300 {
|
||||
background-color: $gray-300 !important;
|
||||
}
|
||||
|
||||
.bg-gray-600 {
|
||||
background-color: $gray-600 !important;
|
||||
}
|
||||
|
||||
.bg-gray-700 {
|
||||
background-color: $gray-700 !important;
|
||||
}
|
||||
|
||||
.bg-green-10 {
|
||||
background-color: $green-10 !important;
|
||||
}
|
||||
|
||||
.bg-green-100 {
|
||||
background-color: $green-100 !important;
|
||||
}
|
||||
|
||||
.bg-purple-100 {
|
||||
background-color: $purple-100 !important;
|
||||
}
|
||||
|
||||
.bg-purple-300 {
|
||||
background-color: $purple-300 !important;
|
||||
}
|
||||
|
||||
.bg-white {
|
||||
background-color: $white !important;
|
||||
}
|
||||
|
||||
.gray-10 {
|
||||
color: $gray-10 !important;
|
||||
}
|
||||
|
||||
.gray-50 {
|
||||
color: $gray-50 !important;
|
||||
}
|
||||
|
||||
.gray-200 {
|
||||
color: $gray-200 !important;
|
||||
}
|
||||
|
||||
.gray-300 {
|
||||
color: $gray-300 !important;
|
||||
}
|
||||
|
||||
.green-10 {
|
||||
color: $green-10 !important;
|
||||
}
|
||||
|
||||
.maroon-50 {
|
||||
color: $maroon-50 !important;
|
||||
}
|
||||
|
||||
.purple-200 {
|
||||
color: $purple-200 !important;
|
||||
}
|
||||
|
||||
.purple-300 {
|
||||
color: $purple-300 !important;
|
||||
}
|
||||
|
||||
.purple-600 {
|
||||
color: $purple-600 !important;
|
||||
}
|
||||
|
||||
.teal-1 {
|
||||
color: $teal-1 !important;
|
||||
}
|
||||
|
||||
.teal-10 {
|
||||
color: $teal-10 !important;
|
||||
}
|
||||
|
||||
.yellow-10 {
|
||||
color: $yellow-10 !important;
|
||||
}
|
||||
|
||||
.white {
|
||||
color: $white !important;
|
||||
}
|
||||
|
||||
32
website/client/src/assets/svg/divider-stars.svg
Normal file
@@ -0,0 +1,32 @@
|
||||
<svg width="40" height="16" viewBox="0 0 40 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.3333 5.33333L12 8L17.3333 10.6667L20 16L22.6667 10.6667L28 8L22.6667 5.33333L20 0L17.3333 5.33333Z" fill="#BDA8FF"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M25 7.99984L21.6667 9.6665L20 7.99984L25 7.99984Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M20 3L21.6666 6.33333L20 8V3Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M15 8L18.3333 6.33333L20 8L15 8Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M20 13L18.3333 9.66667L20 8V13Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M15 7.99984L18.3333 9.6665L20 7.99984L15 7.99984Z" fill="#925CF3"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M20 3L18.3333 6.33333L20 8V3Z" fill="#925CF3"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M25 8L21.6667 6.33333L20 8L25 8Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M20 13L21.6666 9.66667L20 8V13Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M20.7999 7.20041L22.3333 8.00041L20.7999 8.80041L19.9999 10.3337L19.1999 8.80041L17.6666 8.00041L19.1999 7.20041L19.9999 5.66707L20.7999 7.20041Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.66667 6.66667L0 8L2.66667 9.33333L4 12L5.33333 9.33333L8 8L5.33333 6.66667L4 4L2.66667 6.66667Z" fill="#925CF3"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M6.49976 7.99967L4.83309 8.83301L3.99976 7.99967H6.49976Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M3.99998 5.5L4.83331 7.16667L3.99998 8L3.99998 5.5Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M1.5 8L3.16667 7.16667L4 8H1.5Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M4 10.5L3.16667 8.83333L4 8V10.5Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M1.50018 7.99967L3.16685 8.83301L4.00018 7.99967H1.50018Z" fill="#6133B4"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M4 5.5L3.16667 7.16667L4 8V5.5Z" fill="#6133B4"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M6.5 8L4.83333 7.16667L4 8H6.5Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M3.99998 10.5L4.83331 8.83333L3.99998 8L3.99998 10.5Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M4.40002 7.59935L5.16669 7.99935L4.40002 8.39935L4.00002 9.16602L3.60002 8.39935L2.83335 7.99935L3.60002 7.59935L4.00002 6.83268L4.40002 7.59935Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M34.6667 6.66667L32 8L34.6667 9.33333L36 12L37.3333 9.33333L40 8L37.3333 6.66667L36 4L34.6667 6.66667Z" fill="#925CF3"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M38.4998 7.99967L36.8331 8.83301L35.9998 7.99967H38.4998Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M36 5.5L36.8333 7.16667L36 8V5.5Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M33.5 8L35.1667 7.16667L36 8H33.5Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M36 10.5L35.1667 8.83333L36 8V10.5Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M33.5002 7.99967L35.1668 8.83301L36.0002 7.99967H33.5002Z" fill="#6133B4"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M36 5.5L35.1667 7.16667L36 8V5.5Z" fill="#6133B4"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M38.5 8L36.8333 7.16667L36 8H38.5Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M36 10.5L36.8333 8.83333L36 8V10.5Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M36.4 7.59935L37.1667 7.99935L36.4 8.39935L36 9.16602L35.6 8.39935L34.8334 7.99935L35.6 7.59935L36 6.83268L36.4 7.59935Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
@@ -1,7 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 144 31">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path fill="#FFF" d="M120.876 24.007a2.27 2.27 0 0 0-3.183.41 4.595 4.595 0 0 1-3.663 1.804 4.62 4.62 0 0 1-4.613-4.335c-.005-.35-.009-2.864-.009-3.19a4.627 4.627 0 0 1 4.622-4.622c1.28 0 2.47.51 3.353 1.44a2.269 2.269 0 0 0 3.29-3.125 9.2 9.2 0 0 0-6.643-2.853c-5.05 0-9.16 4.109-9.16 9.16 0 .03.002 3.175.014 3.406a9.158 9.158 0 0 0 9.146 8.657 9.1 9.1 0 0 0 7.257-3.57 2.27 2.27 0 0 0-.411-3.182M134.373 26.221a4.62 4.62 0 0 1-4.613-4.333c-.005-.353-.008-2.877-.008-3.193a4.627 4.627 0 0 1 4.621-4.622 4.627 4.627 0 0 1 4.622 4.622c0 .328-.003 2.84-.009 3.189a4.618 4.618 0 0 1-4.613 4.337m6.891-17.078a2.264 2.264 0 0 0-2.19 1.706 9.095 9.095 0 0 0-4.7-1.313c-5.051 0-9.16 4.109-9.16 9.16 0 .031.001 3.173.013 3.406a9.158 9.158 0 0 0 9.146 8.657 9.118 9.118 0 0 0 4.81-1.37 2.268 2.268 0 0 0 4.35-.899V11.412a2.27 2.27 0 0 0-2.269-2.269M30.546 26.221a4.62 4.62 0 0 1-4.613-4.335c-.006-.35-.01-2.863-.01-3.19a4.627 4.627 0 0 1 4.623-4.623 4.627 4.627 0 0 1 4.622 4.622c0 .328-.004 2.84-.01 3.189a4.618 4.618 0 0 1-4.612 4.337m6.89-17.078a2.264 2.264 0 0 0-2.19 1.706 9.095 9.095 0 0 0-4.7-1.313c-5.052 0-9.16 4.109-9.16 9.16 0 .031 0 3.174.013 3.406a9.158 9.158 0 0 0 9.147 8.657 9.118 9.118 0 0 0 4.809-1.37 2.268 2.268 0 0 0 4.35-.899V11.412a2.27 2.27 0 0 0-2.269-2.269M70.84 9.143a2.27 2.27 0 0 0-2.27 2.27V28.49a2.27 2.27 0 0 0 4.539 0V11.412a2.27 2.27 0 0 0-2.27-2.269M97.563 9.143a2.27 2.27 0 0 0-2.27 2.27V28.49a2.27 2.27 0 0 0 4.538 0V11.412a2.27 2.27 0 0 0-2.268-2.269M59.066 21.888a4.62 4.62 0 0 1-4.613 4.333 4.62 4.62 0 0 1-4.613-4.338c-.006-.35-.009-2.86-.009-3.187a4.627 4.627 0 0 1 4.622-4.622 4.627 4.627 0 0 1 4.622 4.622c0 .315-.004 2.84-.009 3.192M54.453 9.536a9.089 9.089 0 0 0-4.622 1.265V2.33a2.27 2.27 0 0 0-4.537 0V28.49a2.269 2.269 0 0 0 4.35.9 9.117 9.117 0 0 0 4.81 1.37 9.16 9.16 0 0 0 9.146-8.666c.011-.224.013-3.367.013-3.398 0-5.052-4.11-9.16-9.16-9.16M8.92 9.536a9.143 9.143 0 0 0-4.382 1.11V2.33A2.27 2.27 0 0 0 0 2.33v26.16a2.269 2.269 0 1 0 4.538 0V16.763c.173-.147.333-.314.46-.516a4.601 4.601 0 0 1 3.921-2.173 4.627 4.627 0 0 1 4.622 4.622c0 .415-.004 9.233-.01 9.738a2.27 2.27 0 0 0 4.535.172c.01-.225.012-9.814.012-9.91 0-5.052-4.108-9.16-9.159-9.16M88.95 9.143h-2.648V2.33a2.27 2.27 0 0 0-4.538 0v6.813h-2.647a2.27 2.27 0 0 0 0 4.538h2.647V28.49a2.27 2.27 0 0 0 4.538 0V13.681h2.647a2.27 2.27 0 0 0 0-4.538"/>
|
||||
<path fill="#FF6066" d="M73.025 2.33a2.27 2.27 0 1 1-4.538 0 2.27 2.27 0 0 1 4.538 0"/>
|
||||
<path fill="#4FB5E8" d="M99.748 2.33a2.27 2.27 0 1 1-4.539 0 2.27 2.27 0 0 1 4.539 0"/>
|
||||
</g>
|
||||
<svg width="217" height="48" viewBox="0 0 217 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M108.785 0.0195312C106.343 0.0195312 104.355 1.99967 104.355 4.44184C104.355 6.88401 106.343 8.86415 108.785 8.86415C111.227 8.86415 113.215 6.87668 113.215 4.44184C113.215 2.007 111.227 0.0195312 108.785 0.0195312Z" fill="#FF6165"/>
|
||||
<path d="M148.564 0.0195312C146.121 0.0195312 144.134 1.99967 144.134 4.44184C144.134 6.88401 146.121 8.86415 148.564 8.86415C151.006 8.86415 152.993 6.87668 152.993 4.44184C152.993 2.007 151.006 0.0195312 148.564 0.0195312Z" fill="#50B5E9"/>
|
||||
<path d="M184.2 42.1989C181.332 45.8879 177.005 48 172.319 48C164.355 48 157.776 41.8176 157.344 33.9264C157.322 33.5303 157.322 28.8367 157.322 28.7927C157.322 20.5788 164.047 13.8976 172.319 13.8976C176.411 13.8976 180.379 15.5917 183.195 18.54C184.053 19.4347 184.515 20.6154 184.478 21.8548C184.449 23.0943 183.928 24.2457 183.019 25.0964C181.156 26.8565 178.201 26.7759 176.426 24.9277C175.341 23.7983 173.881 23.1749 172.312 23.1749C169.188 23.1749 166.65 25.6904 166.65 28.7853C166.65 29.2694 166.65 32.995 166.665 33.5083C166.841 36.4052 169.327 38.7154 172.312 38.7154C174.087 38.7154 175.722 37.916 176.8 36.5225C178.369 34.4984 181.31 34.1244 183.342 35.6865C184.332 36.4419 184.962 37.5346 185.124 38.7667C185.285 39.9988 184.948 41.2162 184.192 42.1989H184.2ZM216.82 18.4739V43.4164C216.82 45.9392 214.774 47.9927 212.258 47.9927C210.916 47.9927 209.669 47.3986 208.819 46.4159C206.787 47.45 204.543 47.9927 202.262 47.9927C194.533 47.9927 188.145 41.9129 187.727 34.1464C187.705 33.7577 187.705 29.152 187.705 29.1007C187.705 21.0261 194.239 14.4623 202.262 14.4623C204.419 14.4623 206.545 14.9537 208.503 15.8924C209.332 14.6677 210.726 13.8903 212.266 13.8903C214.781 13.8903 216.827 15.9438 216.827 18.4666L216.82 18.4739ZM207.689 33.721C207.697 33.1196 207.704 29.5774 207.704 29.108C207.704 26.0791 205.262 23.6223 202.262 23.6223C199.263 23.6223 196.821 26.0865 196.821 29.108C196.821 29.5701 196.821 33.2443 196.836 33.7577C197.004 36.5812 199.395 38.84 202.262 38.84C205.13 38.84 207.506 36.5959 207.689 33.721ZM63.3042 18.4739V43.4164C63.3042 45.9392 61.2581 47.9927 58.7426 47.9927C57.4006 47.9927 56.1539 47.3986 55.3032 46.4159C53.2717 47.45 51.0276 47.9927 48.7469 47.9927C41.0099 47.9927 34.6296 41.9129 34.2115 34.1464C34.1895 33.8017 34.1895 30.2008 34.1895 29.1007C34.1895 21.0261 40.7238 14.4623 48.7469 14.4623C50.903 14.4623 53.0371 14.9537 54.9878 15.8924C55.8165 14.6677 57.2099 13.8903 58.75 13.8903C61.2654 13.8903 63.3115 15.9438 63.3115 18.4666L63.3042 18.4739ZM48.7469 23.6223C45.7474 23.6223 43.3053 26.0865 43.3053 29.108C43.3053 29.5847 43.3053 33.237 43.32 33.7503C43.4886 36.5812 45.8794 38.84 48.7469 38.84C51.6143 38.84 53.9904 36.5959 54.1738 33.721C54.1811 33.1196 54.1884 29.5847 54.1884 29.108C54.1884 26.0791 51.7463 23.6223 48.7469 23.6223ZM108.78 14.1396C106.338 14.1396 104.351 16.1931 104.351 18.716V43.4164C104.351 45.9392 106.338 47.9927 108.78 47.9927C111.222 47.9927 113.21 45.9392 113.21 43.4164V18.716C113.21 16.1931 111.222 14.1396 108.78 14.1396ZM148.558 14.1396C146.116 14.1396 144.129 16.1931 144.129 18.716V43.4164C144.129 45.9392 146.116 47.9927 148.558 47.9927C151 47.9927 152.988 45.9392 152.988 43.4164V18.716C152.988 16.1931 151 14.1396 148.558 14.1396ZM98.7551 28.866C98.7551 28.91 98.7551 33.5817 98.7331 33.9704C98.3151 41.8396 91.9275 48 84.1978 48C81.917 48 79.6729 47.45 77.6415 46.4012C76.7908 47.3986 75.5441 48 74.1947 48C71.6792 48 69.6331 45.9245 69.6331 43.3797V4.62032C69.6331 2.07548 71.6792 0 74.1947 0C76.7101 0 78.7562 2.07548 78.7562 4.62032V15.1224C80.487 14.411 82.3351 14.037 84.1978 14.037C92.2282 14.037 98.7551 20.6888 98.7551 28.866ZM84.1978 23.285C81.1983 23.285 78.7562 25.7858 78.7562 28.866C78.7562 29.35 78.7562 33.0536 78.7709 33.5743C78.9469 36.4565 81.3303 38.752 84.1978 38.752C87.0653 38.752 89.434 36.4712 89.6247 33.5523C89.6247 32.929 89.6394 29.328 89.6394 28.866C89.6394 25.7858 87.1973 23.285 84.1978 23.285ZM14.3887 14.037C12.6139 14.037 10.8612 14.3597 9.21109 14.9757V4.62766C9.21109 2.08281 7.14299 0.00733401 4.60554 0.00733401C2.06809 0.00733401 0 2.08281 0 4.62766V43.3797C0 45.9319 2.06809 48 4.60554 48C7.14299 48 9.21109 45.9245 9.21109 43.3797V26.5412C9.40176 26.3358 11.1178 23.285 14.3887 23.285C17.4395 23.285 19.9182 25.7858 19.9182 28.866C19.9182 29.482 19.9182 42.529 19.9036 43.2623C19.8376 45.7852 21.759 47.868 24.2524 47.9927C24.3404 47.9927 24.4211 47.9927 24.5091 47.9927C26.9586 47.9927 28.9753 46.0639 29.1 43.607C29.122 43.2257 29.122 29.0053 29.122 28.866C29.122 20.6888 22.5144 14.037 14.3887 14.037ZM136.399 14.037H133.7V4.62032C133.7 2.07548 131.61 0 129.036 0C126.462 0 124.372 2.07548 124.372 4.62032V14.037H121.673C119.106 14.037 117.009 16.1125 117.009 18.6646C117.009 21.2168 119.099 23.285 121.673 23.285H124.372V43.3797C124.372 45.9319 126.462 48 129.036 48C131.61 48 133.7 45.9245 133.7 43.3797V23.285H136.399C138.973 23.285 141.063 21.2095 141.063 18.6646C141.063 16.1198 138.973 14.037 136.399 14.037Z" fill="white"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 4.9 KiB |
48
website/client/src/assets/svg/hourglass-sparkle-left.svg
Normal file
@@ -0,0 +1,48 @@
|
||||
<svg width="53" height="53" viewBox="0 0 53 53" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M32.4728 37.2881L31.0401 40.6634C30.8722 41.0588 30.533 41.3618 30.1106 41.4581C25.4964 42.5161 15.7591 38.3829 13.3131 34.3281C13.0907 33.958 13.073 33.5035 13.2408 33.108L14.6735 29.7328C15.9802 26.6545 18.829 24.3765 21.9907 23.6412C22.9143 23.4268 23.3484 22.4041 22.8611 21.5907C21.1937 18.8056 20.8534 15.174 22.16 12.0957L23.5927 8.72043C23.7606 8.32501 24.0998 8.02203 24.5199 7.92663C29.1358 6.86935 38.8731 11.0026 41.3173 15.0567C41.5422 15.4259 41.5599 15.8804 41.392 16.2758L39.9593 19.651C38.6527 22.7293 35.8039 25.0073 32.6422 25.7426C31.7185 25.957 31.2844 26.9797 31.7718 27.7931C33.4392 30.5782 33.7795 34.2099 32.4728 37.2881Z" fill="#A9DCF6" fill-opacity="0.8"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M32.664 12.0938C29.7729 10.8666 27.3007 10.4316 25.8346 10.5102L24.7036 13.1747C23.7617 15.3938 23.9622 18.0859 25.2286 20.2007C25.9064 21.3331 26.0063 22.7223 25.4978 23.9203C24.9893 25.1182 23.9206 26.0114 22.6375 26.3096C20.2342 26.8686 18.1583 28.5945 17.2171 30.8118L16.0854 33.478C17.0473 34.5873 19.0775 36.0634 21.9686 37.2906C24.8596 38.5178 27.3318 38.9528 28.7979 38.8742L29.9297 36.208C30.8709 33.9906 30.6703 31.2985 29.4039 29.1837C28.7261 28.0513 28.6263 26.662 29.1348 25.4641C29.6433 24.2662 30.7119 23.3729 31.9957 23.0732C34.3983 22.5158 36.4742 20.7899 37.4162 18.5709L38.5472 15.9064C37.5853 14.7971 35.555 13.321 32.664 12.0938Z" fill="white" fill-opacity="0.9"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M31.5684 13.8635C33.7371 14.784 35.9512 15.9582 35.7471 16.4997C35.5853 16.9371 35.2218 17.7653 33.0852 17.902C31.0091 18.0368 30.0196 19.4736 29.0902 19.0791C28.0092 18.6202 28.3314 17.6878 27.3948 16.2289C26.429 14.7261 26.743 13.3826 26.9685 12.8935C27.2828 12.2137 29.3996 12.9429 31.5684 13.8635Z" fill="#9A62FF"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M27.3942 16.2291C26.4285 14.7263 26.7424 13.3828 26.9679 12.8937C27.2164 12.3553 28.5959 12.7006 30.2369 13.3243C29.6862 13.3623 28.8925 13.5984 28.6315 14.6159C28.3585 15.6755 29.4738 17.4486 28.8447 18.2192C28.7229 18.3703 28.5806 18.4714 28.4271 18.5381C28.0907 18.0153 28.0509 17.2522 27.3942 16.2291Z" fill="#4F2A93"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.3429 26.9852C27.003 27.2653 26.6667 28.5305 27.3103 29.6779C28.1003 31.0844 28.7422 32.6761 28.3659 34.4146C28.0561 35.8466 27.757 35.9145 27.4109 35.8779C27.0665 35.842 24.5481 35.2396 22.4522 33.773C20.3546 32.3057 19.4609 30.8532 20.0783 30.0166C20.6666 29.2207 21.6339 28.7393 23.1921 28.369C24.6835 28.0155 25.6829 26.705 26.3429 26.9852Z" fill="#9A62FF"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M27.4114 35.8785C27.0653 35.8419 24.5469 35.2396 22.451 33.773C20.7841 32.6066 19.878 31.4501 19.8876 30.6036C19.8956 30.5893 19.9037 30.575 19.9144 30.5637C20.2509 30.1316 22.3027 30.658 24.5368 32.0612C26.6666 33.3964 28.1998 34.9294 27.8338 35.7684C27.6986 35.8902 27.5598 35.8942 27.4114 35.8785Z" fill="#4F2A93"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.80368 18.2264L8.2016e-05 20.1109L3.80368 21.9953L5.70549 25.7643L7.60729 21.9953L11.4109 20.1109L7.60729 18.2264L5.70549 14.4574L3.80368 18.2264Z" fill="#925CF3"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M9.27148 20.1109L6.89423 21.2887L5.70561 20.1109H9.27148Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M5.70542 16.5775L6.89404 18.933L5.70542 20.1108V16.5775Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M2.13969 20.1108L4.51694 18.933L5.70557 20.1108H2.13969Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M5.70557 23.6443L4.51694 21.2887L5.70557 20.1109V23.6443Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M2.13969 20.1109L4.51694 21.2887L5.70557 20.1109H2.13969Z" fill="#6133B4"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M5.70557 16.5775L4.51694 18.933L5.70557 20.1108V16.5775Z" fill="#6133B4"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M9.27148 20.1108L6.89423 18.933L5.70561 20.1108H9.27148Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M5.70542 23.6443L6.89404 21.2887L5.70542 20.1109V23.6443Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M6.27609 19.5455L7.36963 20.1109L6.27609 20.6762L5.70555 21.7598L5.13501 20.6762L4.04148 20.1109L5.13501 19.5455L5.70555 18.4619L6.27609 19.5455Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.8625 1.53112L11.3172 2.29668L12.8625 3.06225L13.6351 4.59338L14.4077 3.06225L15.9529 2.29668L14.4077 1.53112L13.6351 -1.81198e-05L12.8625 1.53112Z" fill="#BDA8FF"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M15.0837 2.29667L14.118 2.77515L13.6351 2.29667H15.0837Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M13.635 0.861193L14.1179 1.81815L13.635 2.29663V0.861193Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M12.1864 2.29663L13.1521 1.81815L13.635 2.29663H12.1864Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M13.635 3.73218L13.1521 2.77522L13.635 2.29674V3.73218Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M12.1864 2.29667L13.1521 2.77515L13.635 2.29667H12.1864Z" fill="#925CF3"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M13.635 0.861193L13.1521 1.81815L13.635 2.29663V0.861193Z" fill="#925CF3"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M15.0837 2.29663L14.118 1.81815L13.6351 2.29663H15.0837Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M13.635 3.73218L14.1179 2.77522L13.635 2.29674V3.73218Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M13.8668 2.06701L14.311 2.29668L13.8668 2.52635L13.635 2.96655L13.4032 2.52635L12.959 2.29668L13.4032 2.06701L13.635 1.62681L13.8668 2.06701Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M48.2455 29.7042L45.8682 30.882L48.2455 32.0598L49.4341 34.4154L50.6227 32.0598L53 30.882L50.6227 29.7042L49.4341 27.3486L48.2455 29.7042Z" fill="#925CF3"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M51.6628 30.882L50.1771 31.6182L49.4342 30.882H51.6628Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M49.4341 28.6737L50.177 30.146L49.4341 30.8821V28.6737Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M47.2054 30.8821L48.6912 30.146L49.4341 30.8821H47.2054Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M49.4341 33.0903L48.6912 31.6181L49.4341 30.882V33.0903Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M47.2054 30.882L48.6912 31.6182L49.4341 30.882H47.2054Z" fill="#6133B4"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M49.4341 28.6737L48.6912 30.146L49.4341 30.8821V28.6737Z" fill="#6133B4"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M51.6628 30.8821L50.1771 30.146L49.4342 30.8821H51.6628Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M49.4341 33.0903L50.177 31.6181L49.4341 30.882V33.0903Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M49.7907 30.5287L50.4741 30.882L49.7907 31.2354L49.4341 31.9126L49.0775 31.2354L48.394 30.882L49.0775 30.5287L49.4341 29.8515L49.7907 30.5287Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M39.9456 43.5776L35.1911 45.9332L39.9456 48.2888L42.3228 53L44.7001 48.2888L49.4546 45.9332L44.7001 43.5776L42.3228 38.8665L39.9456 43.5776Z" fill="#6133B4"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M46.7803 45.9333L43.8087 47.4055L42.3229 45.9333H46.7803Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M42.3228 41.5165L43.8086 44.461L42.3228 45.9332V41.5165Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M37.8654 45.9332L40.837 44.461L42.3228 45.9332H37.8654Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M42.3228 50.35L40.837 47.4055L42.3228 45.9332V50.35Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M37.8654 45.9333L40.837 47.4055L42.3228 45.9333H37.8654Z" fill="#4F2A93"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M42.3228 41.5165L40.837 44.461L42.3228 45.9332V41.5165Z" fill="#4F2A93"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M46.7803 45.9332L43.8087 44.461L42.3229 45.9332H46.7803Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M42.3228 50.35L43.8086 47.4055L42.3228 45.9332V50.35Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M43.0359 45.2266L44.4028 45.9332L43.0359 46.6399L42.3227 47.9944L41.6096 46.6399L40.2426 45.9332L41.6096 45.2266L42.3227 43.8721L43.0359 45.2266Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.0 KiB |
48
website/client/src/assets/svg/hourglass-sparkle-right.svg
Normal file
@@ -0,0 +1,48 @@
|
||||
<svg width="53" height="53" viewBox="0 0 53 53" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M21.5272 37.2881L22.9599 40.6634C23.1278 41.0588 23.467 41.3618 23.8894 41.4581C28.5036 42.5161 38.2409 38.3829 40.6869 34.3281C40.9093 33.958 40.927 33.5035 40.7592 33.108L39.3265 29.7328C38.0198 26.6545 35.171 24.3765 32.0093 23.6412C31.0857 23.4268 30.6516 22.4041 31.1389 21.5907C32.8063 18.8056 33.1466 15.174 31.84 12.0957L30.4073 8.72043C30.2394 8.32501 29.9002 8.02203 29.4801 7.92663C24.8642 6.86935 15.1269 11.0026 12.6827 15.0567C12.4578 15.4259 12.4401 15.8804 12.608 16.2758L14.0407 19.651C15.3473 22.7293 18.1961 25.0073 21.3578 25.7426C22.2815 25.957 22.7156 26.9797 22.2282 27.7931C20.5608 30.5782 20.2205 34.2099 21.5272 37.2881Z" fill="#A9DCF6" fill-opacity="0.8"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M21.336 12.0938C24.2271 10.8666 26.6993 10.4316 28.1654 10.5102L29.2964 13.1747C30.2383 15.3938 30.0378 18.0859 28.7714 20.2007C28.0936 21.3331 27.9937 22.7223 28.5022 23.9203C29.0107 25.1182 30.0794 26.0114 31.3625 26.3096C33.7658 26.8686 35.8417 28.5945 36.7829 30.8118L37.9146 33.478C36.9527 34.5873 34.9225 36.0634 32.0314 37.2906C29.1404 38.5178 26.6682 38.9528 25.2021 38.8742L24.0703 36.208C23.1291 33.9906 23.3297 31.2985 24.5961 29.1837C25.2739 28.0513 25.3737 26.662 24.8652 25.4641C24.3567 24.2662 23.2881 23.3729 22.0043 23.0732C19.6017 22.5158 17.5258 20.7899 16.5838 18.5709L15.4528 15.9064C16.4147 14.7971 18.445 13.321 21.336 12.0938Z" fill="white" fill-opacity="0.9"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M22.4316 13.8635C20.2629 14.784 18.0488 15.9582 18.2529 16.4997C18.4147 16.9371 18.7782 17.7653 20.9148 17.902C22.9909 18.0368 23.9804 19.4736 24.9098 19.0791C25.9908 18.6202 25.6686 17.6878 26.6052 16.2289C27.571 14.7261 27.257 13.3826 27.0315 12.8935C26.7172 12.2137 24.6004 12.9429 22.4316 13.8635Z" fill="#9A62FF"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.6058 16.2291C27.5715 14.7263 27.2576 13.3828 27.0321 12.8937C26.7836 12.3553 25.4041 12.7006 23.7631 13.3243C24.3138 13.3623 25.1075 13.5984 25.3685 14.6159C25.6415 15.6755 24.5262 17.4486 25.1553 18.2192C25.2771 18.3703 25.4194 18.4714 25.5729 18.5381C25.9093 18.0153 25.9491 17.2522 26.6058 16.2291Z" fill="#4F2A93"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M27.6571 26.9852C26.997 27.2653 27.3333 28.5305 26.6897 29.6779C25.8997 31.0844 25.2578 32.6761 25.6341 34.4146C25.9439 35.8466 26.243 35.9145 26.5891 35.8779C26.9335 35.842 29.4519 35.2396 31.5478 33.773C33.6454 32.3057 34.5391 30.8532 33.9217 30.0166C33.3334 29.2207 32.3661 28.7393 30.8079 28.369C29.3165 28.0155 28.3171 26.705 27.6571 26.9852Z" fill="#9A62FF"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.5886 35.8785C26.9347 35.8419 29.4531 35.2396 31.549 33.773C33.2159 32.6066 34.122 31.4501 34.1124 30.6036C34.1044 30.5893 34.0963 30.575 34.0856 30.5637C33.7491 30.1316 31.6973 30.658 29.4632 32.0612C27.3334 33.3964 25.8002 34.9294 26.1662 35.7684C26.3014 35.8902 26.4402 35.8942 26.5886 35.8785Z" fill="#4F2A93"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 30L15 32.5L10 35L7.5 40L5 35L0 32.5L5 30L7.5 25L10 30Z" fill="#925CF3"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M3 32L6.33333 34L8 32H3Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M8 27L6 30.3333L8 32L8 27Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M12 32L8.66667 30L7 32H12Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M7 37L9 33.6667L7 32L7 37Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M12 32L8.66667 34L7 32H12Z" fill="#6133B4"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M7 27L9 30.3333L7 32L7 27Z" fill="#6133B4"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M3 32L6.33333 30L8 32H3Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M8 37L6 33.6667L8 32L8 37Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M6.31429 31.3143L5 32L6.31429 32.6857L7 34L7.68571 32.6857L9 32L7.68571 31.3143L7 30L6.31429 31.3143Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.3333 47.6667L21 49L18.3333 50.3333L17 53L15.6667 50.3333L13 49L15.6667 47.6667L17 45L18.3333 47.6667Z" fill="#BDA8FF"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M14 49L16 50L17 49H14Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M17 46L16 48L17 49V46Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M20 49L18 48L17 49H20Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M17 52L18 50L17 49V52Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M20 49L18 50L17 49H20Z" fill="#925CF3"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M17 46L18 48L17 49V46Z" fill="#925CF3"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M14 49L16 48L17 49H14Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M17 52L16 50L17 49V52Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M16.9857 48.9857L16 49.5L16.9857 50.0143L17.5 51L18.0143 50.0143L19 49.5L18.0143 48.9857L17.5 48L16.9857 48.9857Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M40 2L42 3L40 4L39 6L38 4L36 3L38 2L39 0L40 2Z" fill="#925CF3"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M37 3L38.3333 4L39 3H37Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M39 1L38 2.33333L39 3V1Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M41 3L39.6667 2L39 3L41 3Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M39 5L40 3.66667L39 3V5Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M41 3L39.6667 4L39 3H41Z" fill="#6133B4"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M39 1L40 2.33333L39 3V1Z" fill="#6133B4"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M37 3L38.3333 2L39 3L37 3Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M39 5L38 3.66667L39 3V5Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M38.6571 2.65714L38 3L38.6571 3.34286L39 4L39.3429 3.34286L40 3L39.3429 2.65714L39 2L38.6571 2.65714Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M49 21L53 23L49 25L47 29L45 25L41 23L45 21L47 17L49 21Z" fill="#6133B4"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M43 23L45.6667 24L47 23H43Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M46 19L45 21.6667L46 23V19Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M50 23L47.3333 22L46 23H50Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M47 27L48 24.3333L47 23V27Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M50 23L47.3333 24L46 23H50Z" fill="#4F2A93"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M47 19L48 21.6667L47 23V19Z" fill="#4F2A93"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M43 23L45.6667 22L47 23H43Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M46 27L45 24.3333L46 23V27Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M46.3143 21.9857L45 22.5L46.3143 23.0143L47 24L47.6857 23.0143L49 22.5L47.6857 21.9857L47 21L46.3143 21.9857Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.6 KiB |
9
website/client/src/assets/svg/jackalope.svg
Normal file
@@ -0,0 +1,9 @@
|
||||
<svg width="38" height="44" viewBox="0 0 38 44" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect width="38" height="44" fill="url(#pattern0_1325_164)"/>
|
||||
<defs>
|
||||
<pattern id="pattern0_1325_164" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_1325_164" transform="scale(0.0263158 0.0227273)"/>
|
||||
</pattern>
|
||||
<image id="image0_1325_164" width="38" height="44" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAsCAYAAAAJpsrIAAAAAXNSR0IArs4c6QAAAn5JREFUWAnV1T1uFEEUBOAJwDEHICBFWomEE5BwDbiCAydOLRGSkRGQOOIYRGRIyEcgIbGFZIeN2tpvtBRqesx4lwbpqfb9Vm0xO56mzr9y87bUaI09fjCVGq2+em+ux+POjL2FHqFDvbkejzvT9fdXpcaLzXQbc2P7AdHp5qLUkPfmpunW3d8cxoM378y5AQtzY/uBkIMLuzifSg2CCE1Bn95flRrq5qH68dPPpYZ5zrlrPnnVZ8wBBxBxCpH6fGD7Qf3ehPkvJNDDiYiwFNwSZs4X4Zi7ePDmnTk3YMGBfy6MQgKhbw4JJ9geVDdnD7oL7XXRAnQQIiQgD6qbswfdhbm/OHcgiQjIQ+qE2HMn5/86dxABQgLysLo5e+7k/OrcYYiYEKhuDq4W0DqAABJAEFQ3B1t3V9cRv35+Xmp4gbbw7Nm3UsP7a7WA1oHhhKUgjnHi45vLshvqHIPqrS9+5/rBhSHsKTXHKe5w4MPJZdkNdXN3dgzhMMIIyj/SBOonbp48KjV23amfXx4d/RLZ56D7TUQ4rDAvQgI54lnyfpJDc+9OvpQ/BQOaDmXDwrDCfnx9WGpwwK8nnco8nbOfmIZ0c44NJ4xyAjkC0zlznIKezXwk5PbwLUaLBMHhhHEiBfoC+hyB6Zy6vcVOGbRICGI558zpI4Z7E4aQIEiQ3JwfDWGJ+vYZsRgtIiQA6svNIU5Bcn37iwUZtIgQEqIv14cEeH/J8xHAtxgRI4KE6Mv1ISH3Lsw3IAAiJkhdrg8J01/t2PDCUiAnOCBvObc3x4YXlgI5lMhJuHfHhhdGYCLnPHMc8ys8mHP/jTBCOZfY6qvvHVOQHLEcqvfwJ8mbnKIO4lmnAAAAAElFTkSuQmCC"/>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
52
website/client/src/assets/svg/stars-purple.svg
Normal file
@@ -0,0 +1,52 @@
|
||||
<svg width="41" height="61" viewBox="0 0 41 61" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.53642 4.26827L12.8046 6.40237L8.53642 8.53648L6.40232 12.8047L4.26821 8.53648L0 6.40237L4.26821 4.26827L6.40232 5.72205e-05L8.53642 4.26827Z" fill="#6133B4"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M2.40088 6.40239L5.06851 7.73621L6.40233 6.40239H2.40088Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M6.4023 2.4009L5.06848 5.06853L6.4023 6.40234V2.4009Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M10.4038 6.40234L7.73616 5.06853L6.40234 6.40234L10.4038 6.40234Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M6.40234 10.4038L7.73616 7.73618L6.40234 6.40236L6.40234 10.4038Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M10.4038 6.40239L7.73616 7.73621L6.40234 6.40239H10.4038Z" fill="#4F2A93"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M6.40234 2.4009L7.73616 5.06853L6.40234 6.40234L6.40234 2.4009Z" fill="#4F2A93"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M2.40088 6.40234L5.06851 5.06853L6.40233 6.40234L2.40088 6.40234Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M6.4023 10.4038L5.06848 7.73618L6.4023 6.40236V10.4038Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M5.76208 5.7622L4.53497 6.40243L5.76208 7.04267L6.40232 8.26978L7.04255 7.04267L8.26966 6.40243L7.04255 5.7622L6.40232 4.53509L5.76208 5.7622Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M37.5385 14.2663L39.8368 15.4154L37.5385 16.5645L36.3894 18.8628L35.2402 16.5645L32.942 15.4154L35.2402 14.2663L36.3894 11.968L37.5385 14.2663Z" fill="#925CF3"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M34.2347 15.4153L35.6712 16.1335L36.3894 15.4153H34.2347Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M36.3894 13.2608L35.6711 14.6972L36.3894 15.4154V13.2608Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M38.544 15.4154L37.1076 14.6972L36.3893 15.4154H38.544Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M36.3893 17.5701L37.1076 16.1337L36.3893 15.4154V17.5701Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M38.544 15.4153L37.1076 16.1335L36.3893 15.4153H38.544Z" fill="#6133B4"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M36.3893 13.2608L37.1076 14.6972L36.3893 15.4154V13.2608Z" fill="#6133B4"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M34.2347 15.4154L35.6712 14.6972L36.3894 15.4154H34.2347Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M36.3894 17.5701L35.6711 16.1337L36.3894 15.4154V17.5701Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M36.0446 15.0707L35.3839 15.4154L36.0446 15.7601L36.3893 16.4209L36.7341 15.7601L37.3948 15.4154L36.7341 15.0707L36.3893 14.4099L36.0446 15.0707Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.5354 28.2693L25.7885 30.8959L20.5354 33.5225L17.9088 38.7756L15.2822 33.5225L10.029 30.8959L15.2822 28.2693L17.9088 23.0161L20.5354 28.2693Z" fill="#BDA8FF"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M12.9839 30.8959L16.2671 32.5375L17.9087 30.8959H12.9839Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M17.9088 25.971L16.2672 29.2543L17.9088 30.8959V25.971Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M22.8336 30.8959L19.5504 29.2543L17.9088 30.8959H22.8336Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M17.9088 35.8207L19.5504 32.5374L17.9088 30.8958V35.8207Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M22.8336 30.8959L19.5504 32.5375L17.9088 30.8959H22.8336Z" fill="#925CF3"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M17.9088 25.971L19.5504 29.2543L17.9088 30.8959V25.971Z" fill="#925CF3"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M12.9839 30.8959L16.2671 29.2543L17.9087 30.8959H12.9839Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M17.9088 35.8207L16.2672 32.5374L17.9088 30.8958V35.8207Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M17.1208 30.1078L15.6105 30.8958L17.1208 31.6838L17.9087 33.1941L18.6967 31.6838L20.207 30.8958L18.6967 30.1078L17.9087 28.5976L17.1208 30.1078Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.53742 54.2673L10.8207 55.9089L7.53742 57.5505L5.8958 60.8337L4.25419 57.5505L0.970947 55.9089L4.25419 54.2673L5.8958 50.984L7.53742 54.2673Z" fill="#925CF3"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M2.81775 55.9089L4.86977 56.9349L5.89579 55.9089H2.81775Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M5.89582 52.8309L4.86981 54.8829L5.89582 55.9089V52.8309Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M8.97385 55.9089L6.92183 54.8829L5.89581 55.9089H8.97385Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M5.89581 58.9869L6.92183 56.9349L5.89581 55.9089V58.9869Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M8.97385 55.9089L6.92183 56.9349L5.89581 55.9089H8.97385Z" fill="#6133B4"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M5.89581 52.8309L6.92183 54.8829L5.89581 55.9089V52.8309Z" fill="#6133B4"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M2.81775 55.9089L4.86977 54.8829L5.89579 55.9089H2.81775Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M5.89582 58.9869L4.86981 56.9349L5.89582 55.9089V58.9869Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M5.40334 55.4164L4.45941 55.9089L5.40334 56.4014L5.89583 57.3453L6.38831 56.4014L7.33225 55.9089L6.38831 55.4164L5.89583 54.4725L5.40334 55.4164Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M37.5374 44.2673L40.8207 45.9089L37.5374 47.5505L35.8958 50.8337L34.2542 47.5505L30.9709 45.9089L34.2542 44.2673L35.8958 40.984L37.5374 44.2673Z" fill="#6133B4"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M32.8177 45.9089L34.8698 46.9349L35.8958 45.9089H32.8177Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M35.8958 42.8309L34.8698 44.8829L35.8958 45.9089V42.8309Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M38.9738 45.9089L36.9218 44.8829L35.8958 45.9089H38.9738Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M35.8958 48.9869L36.9218 46.9349L35.8958 45.9089V48.9869Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M38.9738 45.9089L36.9218 46.9349L35.8958 45.9089H38.9738Z" fill="#4F2A93"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M35.8958 42.8309L36.9218 44.8829L35.8958 45.9089V42.8309Z" fill="#4F2A93"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M32.8177 45.9089L34.8698 44.8829L35.8958 45.9089H32.8177Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M35.8958 48.9869L34.8698 46.9349L35.8958 45.9089V48.9869Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M35.4033 45.4164L34.4594 45.9089L35.4033 46.4014L35.8958 47.3453L36.3883 46.4014L37.3322 45.9089L36.3883 45.4164L35.8958 44.4725L35.4033 45.4164Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.6 KiB |
19
website/client/src/assets/svg/subscriber-food.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<svg width="60" height="58" viewBox="0 0 60 58" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<rect x="38" y="6" width="22" height="26" fill="url(#pattern0_1327_256)"/>
|
||||
<rect width="26" height="26" fill="url(#pattern1_1327_256)"/>
|
||||
<rect x="8" y="36" width="30" height="22" fill="url(#pattern2_1327_256)"/>
|
||||
<defs>
|
||||
<pattern id="pattern0_1327_256" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image0_1327_256" transform="scale(0.0454545 0.0384615)"/>
|
||||
</pattern>
|
||||
<pattern id="pattern1_1327_256" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image1_1327_256" transform="scale(0.0384615)"/>
|
||||
</pattern>
|
||||
<pattern id="pattern2_1327_256" patternContentUnits="objectBoundingBox" width="1" height="1">
|
||||
<use xlink:href="#image2_1327_256" transform="scale(0.0333333 0.0454545)"/>
|
||||
</pattern>
|
||||
<image id="image0_1327_256" width="22" height="26" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAaCAYAAACzdqxAAAAAAXNSR0IArs4c6QAAAQlJREFUSA290k1qwlAUxfFsp+soXYdzoeAaWqFbcSx14LTQSbuAjruLVgdPnvArcsIjRlOFy8n9+t9jSNcN/B7u7stpDIyf3z6F1ufzN2MyQfvf91LjZ7s6RvZjvZ3m4tVgwN36q9TgkKrT7+ePUsNe06oBi4BUnQ6CE2iBAqXqU5w/5woWDVL1VH2K0wMbAHibfZYa6i01dzsw6y7m5+UfcMxhS3FwO4XJwICc5efFaeqg45uB05m85VCdwd679SqAUgFa2gQDWTQoT82+vOd4crALLtKszx8XpUarb76nFqgB+cVgoFTgp+VLqSHPudE50L+B16+bUsOh0Q5zAWhysEMOyCfTseADSSC3nu5iFacAAAAASUVORK5CYII="/>
|
||||
<image id="image1_1327_256" width="26" height="26" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAAAXNSR0IArs4c6QAAASlJREFUSA3F1DFOw0AQBVDTRhSp6RHUaVLQcAWOECkNR6HiPtRcJl1KqBZtpEfxjbWrxA6WRl8znvl//q7lYYjnbnNb/gpt+e75fV1qqOtrooFEg1k/WygJ73c3pQYB+cUC/y6UTjh6225Ljd0wnMKi3ZhHNZsQYohYvv94LDXUOTm+vpQaXw9Pp1CfdIQQIpRfLIQQOnvEMOv6OWk6MwCTcHYhRwRTwAKJ7uT781BqcKj+e1ecEICzCyGmvFmtSg2bE7Rpbq7P+8m7upoQJ5AjZ5wb2xymg3Q8+ce4upCNc8OWA3Ow6Ujj4kLuiCBsCafjpqPFhaa+vl5hjvX7uPCOUIMB6Agh4sz14xkJZEEjdOaIWmgueUe5RriYUCoT7MWc7857BfQh/gFCaNQahl2u3gAAAABJRU5ErkJggg=="/>
|
||||
<image id="image2_1327_256" width="30" height="22" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAWCAYAAADXYyzPAAAAAXNSR0IArs4c6QAAARRJREFUSA3F08FtAjEUBFCagAYSKd3QAsUgcUkDqSO31JBjLrnSBlJk5MOD1Wgt7Ro5IH2N/cee+bPsbjaDf68vb2Vag+3u8lPTur4zK1cpZJ8y+h+H71LLPs8t3hNITAF8tzEB+PlzKdP6Pf+VWvjE0/6r1Fo9QApNTet6uDHD4/u5zBXeoJm0OzHhOdPawz9sTIBgGnrEyevvtttSi05ivoy3vYMpbAAGyes/bEzIf8YItgYx+C3J0oWLw4wZJHpUkkksoX4inl4zqAOJ/2bsO4MSGkgyifBQ3/lmUoSDDCFB/HDjNGQMDQC9fHgoWBMdbCXFQ4aw29hEhA1gj4f6ifjVSOhpxgZYPXnvBYawV2fpvStxGFyuIXWsWQAAAABJRU5ErkJggg=="/>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
@@ -1,26 +1,29 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 39 44">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path fill="#24CC8F" d="M2.782 35.927l1.867-8.397 12.887-5.47 7.338 4.49-5.967 16.655z"/>
|
||||
<path fill="#FFF" d="M9.147 33.008L6.351 28.98l5.523-2.344zM18.352 29.1l-.955-4.808-5.523 2.344z" opacity=".25"/>
|
||||
<path fill="#FFF" d="M9.147 33.008l2.727-6.372 6.478 2.465zM5.097 34.727L6.35 28.98l2.796 4.028z" opacity=".5"/>
|
||||
<path fill="#1B996B" d="M22.402 27.382l-5.005-3.09.955 4.809zM5.097 34.727l4.05-1.719 8.627 7.528z" opacity=".35"/>
|
||||
<path fill="#FFF" d="M22.402 27.382l-4.05 1.719-.578 11.435z" opacity=".5"/>
|
||||
<path fill="#FFF" d="M9.147 33.008l9.205-3.907-.578 11.435z" opacity=".25"/>
|
||||
<g>
|
||||
<path fill="#24CC8F" d="M23.248 7.266l4.784-3.162 8.714 3.345 1.44 5.55-10.575 5.225z"/>
|
||||
<path fill="#FFF" d="M27.653 8.814l.524-3.227 3.734 1.434zM33.876 11.203l1.77-2.749-3.735-1.433z" opacity=".25"/>
|
||||
<path fill="#FFF" d="M27.653 8.814L31.91 7.02l1.965 4.182zM24.914 7.763l3.263-2.176-.524 3.227z" opacity=".5"/>
|
||||
<path fill="#1B996B" d="M36.615 12.254l-.97-3.8-1.769 2.749zM24.914 7.763l2.739 1.05.65 7.606z" opacity=".35"/>
|
||||
<path fill="#FFF" d="M36.615 12.254l-2.739-1.051-5.572 5.216z" opacity=".5"/>
|
||||
<path fill="#FFF" d="M27.653 8.814l6.223 2.389-5.572 5.216z" opacity=".25"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#24CC8F" d="M.815 5.996l1.58-4L9.185.301l3.273 2.791-4.25 7.758z"/>
|
||||
<path fill="#FFF" d="M4.187 5.052L3.121 2.845l2.911-.726zM9.039 3.843l-.096-2.45-2.91.726z" opacity=".25"/>
|
||||
<path fill="#FFF" d="M4.187 5.052L6.032 2.12 9.04 3.843zM2.053 5.585l1.068-2.74 1.066 2.207z" opacity=".5"/>
|
||||
<path fill="#1B996B" d="M11.173 3.31l-2.23-1.917.096 2.45zM2.053 5.585l2.134-.533L7.86 9.445z" opacity=".35"/>
|
||||
<path fill="#FFF" d="M11.173 3.31l-2.134.533-1.18 5.602z" opacity=".5"/>
|
||||
<path fill="#FFF" d="M4.187 5.052l4.852-1.21-1.18 5.603z" opacity=".25"/>
|
||||
</g>
|
||||
</g>
|
||||
<svg width="54" height="54" viewBox="0 0 54 54" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.89107 26.3989L14.4076 18.6441L33.6795 23.9114L37.9287 35.4286L16.5188 48.8092L4.89107 26.3989Z" fill="#24CC8F"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M14.6023 28.7572L15.0317 21.7734L23.2911 24.0309L14.6023 28.7572Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M28.368 32.5196L31.5505 26.2883L23.2911 24.0309L28.368 32.5196Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M14.6023 28.7573L23.2911 24.031L28.368 32.5197L14.6023 28.7573Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M8.54539 27.1018L15.0317 21.7735L14.6023 28.7572L8.54539 27.1018Z" fill="white"/>
|
||||
<path opacity="0.35" fill-rule="evenodd" clip-rule="evenodd" d="M34.4249 34.1751L31.5505 26.2883L28.368 32.5196L34.4249 34.1751Z" fill="#1B996B"/>
|
||||
<path opacity="0.35" fill-rule="evenodd" clip-rule="evenodd" d="M8.54541 27.1018L14.6023 28.7572L17.6099 44.8171L8.54541 27.1018Z" fill="#1B996B"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M34.4249 34.175L28.368 32.5196L17.6099 44.8171L34.4249 34.175Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M14.6023 28.7573L28.368 32.5197L17.6099 44.8172L14.6023 28.7573Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.2974 3.46554L14.2627 0.349942L21.1938 1.32978L23.1792 5.14526L16.3285 10.7414L11.2974 3.46554Z" fill="#24CC8F"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M14.7769 3.85639L14.6178 1.41003L17.5882 1.82996L14.7769 3.85639Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M19.7277 4.55627L20.5587 2.24989L17.5883 1.82996L19.7277 4.55627Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M14.7769 3.85647L17.5882 1.83004L19.7277 4.55636L14.7769 3.85647Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M12.5986 3.54849L14.6178 1.41008L14.7769 3.85644L12.5986 3.54849Z" fill="white"/>
|
||||
<path opacity="0.35" fill-rule="evenodd" clip-rule="evenodd" d="M21.906 4.86425L20.5587 2.24992L19.7277 4.5563L21.906 4.86425Z" fill="#1B996B"/>
|
||||
<path opacity="0.35" fill-rule="evenodd" clip-rule="evenodd" d="M12.5986 3.54846L14.7769 3.85641L16.5314 9.30565L12.5986 3.54846Z" fill="#1B996B"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M21.906 4.86431L19.7277 4.55636L16.5314 9.30572L21.906 4.86431Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M14.7769 3.85645L19.7277 4.55633L16.5314 9.30568L14.7769 3.85645Z" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M30.8389 13.9788L33.0633 6.97062L44.4487 3.28717L50.3566 7.66432L44.0181 21.3937L30.8389 13.9788Z" fill="#24CC8F"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M36.4789 11.9744L34.4028 8.33398L39.2822 6.75536L36.4789 11.9744Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M44.6113 9.3434L44.1617 5.17675L39.2822 6.75537L44.6113 9.3434Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M36.4789 11.9745L39.2822 6.75541L44.6113 9.34344L36.4789 11.9745Z" fill="white"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M32.9007 13.1321L34.4028 8.33396L36.4789 11.9744L32.9007 13.1321Z" fill="white"/>
|
||||
<path opacity="0.35" fill-rule="evenodd" clip-rule="evenodd" d="M48.1896 8.18571L44.1617 5.17672L44.6113 9.34337L48.1896 8.18571Z" fill="#1B996B"/>
|
||||
<path opacity="0.35" fill-rule="evenodd" clip-rule="evenodd" d="M32.9007 13.1321L36.4789 11.9744L43.2551 19.0353L32.9007 13.1321Z" fill="#1B996B"/>
|
||||
<path opacity="0.5" fill-rule="evenodd" clip-rule="evenodd" d="M48.1896 8.18576L44.6113 9.34342L43.2551 19.0353L48.1896 8.18576Z" fill="white"/>
|
||||
<path opacity="0.25" fill-rule="evenodd" clip-rule="evenodd" d="M36.4789 11.9745L44.6113 9.34345L43.2551 19.0353L36.4789 11.9745Z" fill="white"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 4.0 KiB |
@@ -1,26 +1,20 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 35 47">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path fill="#A9DCF6" fill-opacity=".8" d="M25.955 43.329l-.999 2.352a.939.939 0 0 1-.644.555c-3.194.747-9.918-2.107-11.6-4.923a.941.941 0 0 1-.047-.85l.998-2.351c.911-2.146 2.886-3.738 5.074-4.257a.957.957 0 0 0 .607-1.429c-1.147-1.934-1.374-4.46-.463-6.606l.998-2.352a.937.937 0 0 1 .643-.555c3.195-.746 9.919 2.108 11.6 4.924a.935.935 0 0 1 .049.848l-.999 2.353c-.91 2.145-2.886 3.737-5.074 4.256a.957.957 0 0 0-.606 1.429c1.146 1.934 1.373 4.46.463 6.606"/>
|
||||
<path fill="#FFF" fill-opacity=".9" d="M26.145 25.795c-1.997-.848-3.705-1.145-4.72-1.087l-.788 1.857c-.656 1.547-.524 3.42.347 4.889.466.786.532 1.753.178 2.588a2.881 2.881 0 0 1-1.983 1.669c-1.664.395-3.103 1.6-3.76 3.146l-.788 1.858c.663.77 2.063 1.792 4.06 2.64 1.996.847 3.705 1.144 4.719 1.086l.789-1.858c.656-1.545.523-3.418-.348-4.887a2.883 2.883 0 0 1-.178-2.588 2.886 2.886 0 0 1 1.984-1.67c1.663-.394 3.103-1.6 3.759-3.146l.788-1.857c-.662-.77-2.063-1.793-4.06-2.64"/>
|
||||
<path fill="#9A62FF" d="M25.383 27.029c1.497.636 3.026 1.448 2.883 1.825-.112.305-.366.882-1.844.982-1.436.098-2.123 1.1-2.765.828-.746-.317-.521-.966-1.166-1.98-.664-1.043-.444-1.979-.287-2.32.219-.473 1.681.03 3.179.665"/>
|
||||
<path fill="#4F2A93" d="M22.491 28.685c-.664-1.044-.444-1.98-.287-2.32.173-.376 1.126-.139 2.26.292-.382.027-.93.194-1.114.902-.19.738.576 1.97.14 2.507a.755.755 0 0 1-.29.223c-.231-.363-.257-.894-.709-1.604"/>
|
||||
<path fill="#9A62FF" d="M21.74 36.173c.455.193.22 1.074.662 1.871.543.978.984 2.084.72 3.294-.218.998-.425 1.046-.664 1.021-.238-.024-1.979-.438-3.425-1.454-1.447-1.016-2.062-2.025-1.633-2.608.409-.556 1.079-.893 2.157-1.154 1.032-.25 1.727-1.164 2.182-.97"/>
|
||||
<path fill="#4F2A93" d="M22.458 42.36c-.24-.025-1.98-.439-3.425-1.455-1.15-.807-1.774-1.61-1.766-2.2a.138.138 0 0 1 .019-.027c.233-.302 1.651.06 3.193 1.031 1.47.925 2.526 1.988 2.271 2.573-.093.085-.19.088-.292.077"/>
|
||||
<g>
|
||||
<path fill="#A9DCF6" fill-opacity=".8" d="M12.754 15.163l.61 1.59a.626.626 0 0 1-.052.565c-1.185 1.837-5.732 3.582-7.843 3.01a.627.627 0 0 1-.415-.385l-.61-1.59c-.558-1.45-.348-3.129.461-4.39a.638.638 0 0 0-.37-.967c-1.446-.397-2.725-1.503-3.282-2.954l-.61-1.59a.625.625 0 0 1 .05-.564c1.187-1.837 5.734-3.582 7.844-3.01a.623.623 0 0 1 .416.384l.61 1.59c.557 1.45.347 3.129-.462 4.39a.638.638 0 0 0 .371.967c1.446.397 2.725 1.503 3.282 2.954"/>
|
||||
<path fill="#FFF" fill-opacity=".9" d="M4.725 6.666c-1.35.518-2.307 1.167-2.767 1.665l.482 1.255c.402 1.046 1.333 1.883 2.43 2.184a1.922 1.922 0 0 1 1.284 1.159 1.92 1.92 0 0 1-.178 1.719c-.615.96-.747 2.204-.346 3.249l.483 1.256c.674.062 1.82-.096 3.17-.614 1.349-.518 2.306-1.167 2.765-1.664l-.482-1.257c-.401-1.044-1.332-1.881-2.43-2.182a1.922 1.922 0 0 1-1.284-1.16 1.924 1.924 0 0 1 .178-1.72c.615-.958.747-2.203.346-3.248l-.482-1.256c-.674-.062-1.82.096-3.17.614"/>
|
||||
<path fill="#9A62FF" d="M4.93 7.61c1.013-.388 2.122-.706 2.229-.46.087.199.233.593-.43 1.325-.643.713-.508 1.512-.942 1.678-.505.194-.698-.222-1.476-.41-.802-.192-1.13-.743-1.212-.979-.115-.328.82-.765 1.832-1.153"/>
|
||||
<path fill="#4F2A93" d="M4.31 9.744c-.801-.193-1.129-.743-1.211-.98-.091-.26.476-.587 1.219-.906-.17.19-.357.524-.116.948.25.443 1.188.678 1.228 1.138a.503.503 0 0 1-.036.241c-.28-.067-.537-.31-1.083-.44"/>
|
||||
<path fill="#9A62FF" d="M7.418 13.683c.308-.118.603.413 1.185.59.713.218 1.436.544 1.87 1.247.358.58.28.698.154.797-.125.099-1.15.706-2.315.889-1.165.183-1.926-.016-1.991-.495-.061-.455.104-.927.5-1.552.38-.598.289-1.358.597-1.476"/>
|
||||
<path fill="#4F2A93" d="M10.628 16.317c-.126.1-1.152.707-2.316.89-.926.144-1.597.048-1.866-.238a.092.092 0 0 1-.004-.022c-.027-.253.82-.736 2.01-.984 1.132-.237 2.132-.217 2.28.182-.006.084-.05.13-.104.172"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#A9DCF6" fill-opacity=".8" d="M32.605 10.804l-.31 1.24a.47.47 0 0 1-.275.324c-1.518.619-5.062-.265-6.113-1.524a.47.47 0 0 1-.09-.416l.31-1.24c.281-1.13 1.132-2.07 2.172-2.498a.479.479 0 0 0 .188-.753c-.718-.866-1.027-2.096-.745-3.226l.309-1.24a.469.469 0 0 1 .274-.324c1.519-.619 5.063.265 6.113 1.524.097.114.127.27.09.415l-.308 1.24c-.282 1.13-1.133 2.071-2.173 2.498a.479.479 0 0 0-.188.754c.718.865 1.027 2.095.746 3.226"/>
|
||||
<path fill="#FFF" fill-opacity=".9" d="M31.327 2.13c-1.052-.262-1.92-.276-2.416-.168l-.244.98c-.203.814.009 1.729.554 2.386.292.352.4.824.29 1.264a1.44 1.44 0 0 1-.849.98 2.762 2.762 0 0 0-1.61 1.847l-.244.98c.387.328 1.16.723 2.211.986 1.052.262 1.92.275 2.416.167l.244-.98a2.761 2.761 0 0 0-.554-2.385 1.442 1.442 0 0 1-.29-1.265c.11-.44.427-.806.849-.98a2.76 2.76 0 0 0 1.61-1.847l.244-.979c-.387-.328-1.159-.724-2.211-.986"/>
|
||||
<path fill="#9A62FF" d="M31.047 2.799c.79.197 1.608.478 1.567.676-.032.159-.112.464-.834.629-.701.16-.962.71-1.3.625-.394-.098-.334-.436-.731-.886-.41-.464-.375-.943-.324-1.124.071-.25.833-.117 1.622.08"/>
|
||||
<path fill="#4F2A93" d="M29.749 3.843c-.41-.464-.375-.943-.324-1.124.056-.198.546-.156 1.139-.032-.186.044-.444.169-.48.533-.036.38.44.927.266 1.227a.378.378 0 0 1-.126.133c-.143-.161-.197-.422-.475-.737"/>
|
||||
<path fill="#9A62FF" d="M29.963 7.6c.24.06.193.513.474.872.344.44.648.952.613 1.57-.03.51-.128.55-.248.556-.12.007-1.012-.061-1.805-.45-.794-.388-1.177-.838-1.01-1.16.158-.306.462-.525.974-.739.49-.204.762-.71 1.002-.65"/>
|
||||
<path fill="#4F2A93" d="M30.802 10.599c-.12.006-1.012-.062-1.806-.45-.63-.31-1.002-.657-1.043-.949a.069.069 0 0 1 .007-.015c.091-.167.82-.1 1.657.26.798.341 1.403.784 1.323 1.092-.04.05-.087.059-.138.062"/>
|
||||
</g>
|
||||
</g>
|
||||
<svg width="39" height="54" viewBox="0 0 39 54" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M29.2715 47.841L27.8997 51.0729C27.7389 51.4515 27.4157 51.7423 27.014 51.8357C22.6266 52.8619 13.3878 48.9402 11.0765 45.0707C10.8663 44.7175 10.8509 44.283 11.0117 43.9044L12.3835 40.6724C13.6347 37.7249 16.3485 35.5378 19.3549 34.8248C20.2332 34.6169 20.6488 33.6376 20.1883 32.8614C18.6128 30.2035 18.3009 26.732 19.552 23.7844L20.9239 20.5525C21.0846 20.1739 21.4079 19.8832 21.8073 19.7906C26.1963 18.7652 35.4351 22.6868 37.7447 26.5557C37.9572 26.9079 37.9726 27.3425 37.8119 27.7211L36.4401 30.953C35.1889 33.9005 32.475 36.0876 29.4687 36.8006C28.5904 37.0086 28.1747 37.9879 28.6352 38.7641C30.2107 41.4219 30.5227 44.8934 29.2715 47.841Z" fill="#A9DCF6" fill-opacity="0.8"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M29.5322 23.7497C26.7892 22.5854 24.4416 22.1772 23.0484 22.257L21.9654 24.8083C21.0635 26.9331 21.2456 29.5067 22.4422 31.5248C23.0826 32.6056 23.1732 33.9336 22.6863 35.0807C22.1994 36.2277 21.1812 37.0852 19.9611 37.3743C17.6759 37.9164 15.6981 39.5731 14.7969 41.6963L13.7132 44.2492C14.6236 45.3069 16.548 46.712 19.2911 47.8764C22.0341 49.0407 24.3817 49.4489 25.7749 49.3691L26.8586 46.8162C27.7598 44.693 27.5777 42.1194 26.3811 40.1013C25.7407 39.0206 25.6501 37.6925 26.137 36.5454C26.6239 35.3984 27.6421 34.541 28.8628 34.2503C31.1474 33.7098 33.1252 32.053 34.0271 29.9282L35.1101 27.3769C34.1996 26.3192 32.2753 24.9141 29.5322 23.7497Z" fill="white" fill-opacity="0.9"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M28.4856 25.4452C30.5433 26.3187 32.6433 27.4344 32.4477 27.9529C32.2926 28.3716 31.9446 29.1647 29.9141 29.3021C27.9411 29.4375 26.9965 30.8145 26.1146 30.4401C25.089 30.0048 25.3981 29.1122 24.5127 27.7201C23.5998 26.2862 23.9023 25.0005 24.1181 24.5322C24.4189 23.8812 26.4279 24.5718 28.4856 25.4452Z" fill="#9A62FF"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M24.5124 27.7203C23.5995 26.2864 23.902 25.0008 24.1178 24.5324C24.3555 24.0168 25.6652 24.3427 27.2224 24.9339C26.699 24.9719 25.9442 25.2001 25.693 26.1739C25.4303 27.188 26.4845 28.8798 25.8843 29.6187C25.7681 29.7636 25.6326 29.8607 25.4865 29.925C25.1685 29.4261 25.1331 28.6965 24.5124 27.7203Z" fill="#4F2A93"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.4797 38.0086C24.1059 38.2744 23.7824 39.4852 24.3904 40.5804C25.1366 41.9228 25.7414 43.4428 25.3785 45.1063C25.0797 46.4765 24.7953 46.5424 24.4665 46.5084C24.1394 46.4752 21.7484 45.9071 19.7617 44.5113C17.7733 43.1149 16.9287 41.7288 17.518 40.9269C18.0793 40.164 19 39.7007 20.4816 39.3417C21.8998 38.999 22.8534 37.7428 23.4797 38.0086Z" fill="#9A62FF"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M24.467 46.509C24.1383 46.4751 21.7473 45.907 19.7605 44.5113C18.1804 43.4012 17.3231 42.2982 17.3349 41.4887C17.3426 41.475 17.3503 41.4613 17.3605 41.4506C17.6815 41.0363 19.6294 41.5332 21.7477 42.8679C23.7671 44.138 25.2191 45.599 24.8686 46.4024C24.7398 46.5193 24.6079 46.5236 24.467 46.509Z" fill="#4F2A93"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.8803 22.4748L13.0712 24.6344C13.0936 24.8874 13.0019 25.1397 12.8101 25.3073C10.7172 27.1406 4.54355 27.6865 2.16031 26.249C1.9432 26.1175 1.80861 25.8852 1.78624 25.6322L1.59529 23.4726C1.42114 21.5029 2.26494 19.5229 3.69621 18.2613C4.11444 17.893 4.05658 17.2386 3.5802 16.9493C1.94977 15.9584 0.771638 14.1572 0.597488 12.1876L0.406536 10.0279C0.384166 9.77492 0.475899 9.52258 0.666679 9.35616C2.76071 7.52275 8.93431 6.97689 11.3165 8.41452C11.5346 8.54479 11.6692 8.77712 11.6915 9.03012L11.8825 11.1898C12.0566 13.1594 11.2128 15.1394 9.78156 16.401C9.36333 16.7693 9.42119 17.4238 9.89756 17.713C11.528 18.7039 12.7061 20.5051 12.8803 22.4748Z" fill="#A9DCF6" fill-opacity="0.8"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.02615 9.27039C4.19318 9.43245 2.79533 9.89173 2.05923 10.3398L2.20997 12.0447C2.33551 13.4645 3.18214 14.8141 4.4203 15.5665C5.08317 15.9694 5.51817 16.6668 5.58595 17.4333C5.65372 18.1998 5.34784 18.9628 4.76693 19.4746C3.67901 20.4337 3.08233 21.9109 3.20777 23.3297L3.35861 25.0356C4.16191 25.3476 5.61866 25.5545 7.45163 25.3924C9.2846 25.2303 10.6825 24.7711 11.4186 24.323L11.2677 22.617C11.1423 21.1983 10.2956 19.8487 9.05748 19.0963C8.39461 18.6934 7.95961 17.996 7.89184 17.2295C7.82406 16.463 8.12994 15.7 8.71076 15.1871C9.79877 14.2291 10.3955 12.7519 10.2699 11.332L10.1192 9.62718C9.31587 9.31519 7.85912 9.10832 6.02615 9.27039Z" fill="white" fill-opacity="0.9"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.94818 10.4983C7.32318 10.3767 8.7916 10.3749 8.83559 10.7142C8.87266 10.9875 8.91336 11.5207 7.84673 12.1853C6.81082 12.832 6.69593 13.8567 6.10664 13.9088C5.42128 13.9694 5.33053 13.3933 4.44377 12.8918C3.52987 12.3754 3.32137 11.587 3.30294 11.2691C3.27784 10.8269 4.57319 10.6199 5.94818 10.4983Z" fill="#9A62FF"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M4.44368 12.892C3.52978 12.3757 3.32128 11.5872 3.30285 11.2693C3.28266 10.9193 4.09102 10.7165 5.1113 10.5865C4.83716 10.7592 4.49205 11.1028 4.63795 11.7064C4.78931 12.3353 5.8551 12.9512 5.74257 13.5281C5.72134 13.6408 5.6757 13.7331 5.61477 13.8105C5.29657 13.631 5.06544 13.2437 4.44368 12.892Z" fill="#4F2A93"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.86862 18.7985C7.2871 18.7615 7.46241 19.5152 8.11175 19.9355C8.90824 20.4504 9.67927 21.103 9.96455 22.115C10.1996 22.9484 10.0638 23.067 9.87478 23.1439C9.68684 23.2208 8.21892 23.6056 6.73087 23.4219C5.24175 23.2383 4.37897 22.7283 4.46722 22.1201C4.55161 21.5413 4.91878 21.0215 5.62194 20.3956C6.29524 19.797 6.45015 18.8355 6.86862 18.7985Z" fill="#9A62FF"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.87521 23.1441C9.68621 23.2211 8.21829 23.6059 6.73023 23.4222C5.54676 23.2762 4.75927 22.924 4.53061 22.4795C4.53083 22.4698 4.53104 22.4601 4.53349 22.4512C4.58813 22.1323 5.79395 21.8374 7.33593 21.9495C8.80526 22.0553 10.0208 22.4298 10.0631 22.9694C10.0269 23.0705 9.95622 23.1111 9.87521 23.1441Z" fill="#4F2A93"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M33.9597 9.01912L34.5713 10.2909C34.6429 10.4399 34.6449 10.6147 34.5665 10.7608C33.7119 12.3575 30.0762 14.1058 28.2947 13.7765C28.1323 13.7463 27.9971 13.6356 27.9254 13.4866L27.3139 12.2148C26.7561 11.0549 26.8161 9.65517 27.3987 8.5584C27.569 8.2381 27.3837 7.85272 27.0272 7.78575C25.8067 7.55599 24.676 6.72887 24.1182 5.56895L23.5066 4.29712C23.435 4.14812 23.433 3.97336 23.5111 3.82823C24.3663 2.23116 28.002 0.48293 29.7828 0.812446C29.9456 0.841791 30.0808 0.952458 30.1525 1.10146L30.764 2.37329C31.3218 3.53321 31.2618 4.93289 30.6792 6.02966C30.5089 6.34996 30.6942 6.73535 31.0507 6.80232C32.2712 7.03207 33.4019 7.85919 33.9597 9.01912Z" fill="#A9DCF6" fill-opacity="0.8"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.7563 2.54696C25.6769 3.06602 24.9306 3.66635 24.585 4.10812L25.0678 5.11213C25.4698 5.94828 26.2951 6.5763 27.2218 6.75067C27.7181 6.84413 28.143 7.16925 28.36 7.62065C28.5771 8.07205 28.5657 8.60697 28.3292 9.05198C27.8864 9.8857 27.8617 10.9224 28.2634 11.758L28.7465 12.7626C29.3074 12.7685 30.2423 12.5604 31.3217 12.0414C32.4012 11.5223 33.1474 10.922 33.4931 10.4802L33.01 9.47556C32.6082 8.64004 31.783 8.01202 30.8562 7.83765C30.36 7.74419 29.9351 7.41907 29.718 6.96767C29.5009 6.51628 29.5123 5.98136 29.7485 5.53571C30.1917 4.70262 30.2164 3.66588 29.8143 2.82973L29.3315 1.82572C28.7706 1.81987 27.8358 2.0279 26.7563 2.54696Z" fill="white" fill-opacity="0.9"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.9904 3.31291C27.8001 2.92355 28.6943 2.58571 28.7989 2.78233C28.8841 2.94028 29.0312 3.25581 28.5338 3.90522C28.051 4.53676 28.216 5.18735 27.869 5.35422C27.4654 5.5483 27.278 5.21811 26.6228 5.11596C25.9476 5.011 25.6398 4.57848 25.5557 4.38904C25.439 4.12546 26.1806 3.70228 26.9904 3.31291Z" fill="#9A62FF"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.6228 5.11609C25.9476 5.01113 25.6398 4.57861 25.5557 4.38917C25.4631 4.18057 25.9091 3.8717 26.5008 3.55853C26.3734 3.72661 26.242 4.01506 26.4692 4.3493C26.7057 4.69772 27.4962 4.82848 27.5599 5.20575C27.5728 5.27927 27.5662 5.34594 27.5468 5.40711C27.3118 5.37072 27.0822 5.18777 26.6228 5.11609Z" fill="#4F2A93"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M29.4545 8.15813C29.7009 8.03962 29.9806 8.4586 30.4725 8.56572C31.0758 8.69672 31.6951 8.91751 32.101 9.46854C32.4353 9.92237 32.3797 10.0257 32.2823 10.116C32.1854 10.2059 31.3794 10.7769 30.4308 11.0062C29.4815 11.2359 28.839 11.123 28.7533 10.7323C28.672 10.3604 28.7764 9.9595 29.0613 9.41694C29.3342 8.89791 29.208 8.27663 29.4545 8.15813Z" fill="#9A62FF"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M32.2826 10.1159C32.1851 10.2062 31.3791 10.7772 30.4305 11.0065C29.676 11.1889 29.1155 11.155 28.8743 10.9366C28.8722 10.9307 28.8701 10.9247 28.8696 10.9188C28.8297 10.7119 29.4967 10.2558 30.4617 9.97051C31.3811 9.69797 32.2074 9.64738 32.3569 9.96638C32.3581 10.0363 32.3243 10.0773 32.2826 10.1159Z" fill="#4F2A93"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 8.9 KiB |
@@ -8,7 +8,7 @@
|
||||
:no-close-on-backdrop="true"
|
||||
>
|
||||
<div class="modal-body select-class">
|
||||
<h1 class="header-purple text-center">
|
||||
<h1 class="header-purple text-center mb-0">
|
||||
{{ $t('chooseClass') }}
|
||||
</h1>
|
||||
<div class="container-fluid">
|
||||
@@ -26,7 +26,7 @@
|
||||
:with-background="false"
|
||||
:override-avatar-gear="classGear(heroClass)"
|
||||
:hide-class-badge="true"
|
||||
:sprites-margin="'1.8em 1.5em'"
|
||||
:sprites-margin="'20px 36px 36px 20px'"
|
||||
:override-top-padding="'0px'"
|
||||
:show-visual-buffs="false"
|
||||
:class="selectionBox(selectedClass, heroClass)"
|
||||
@@ -91,7 +91,7 @@
|
||||
<div class="opt-out-wrapper">
|
||||
<span
|
||||
id="classOptOutBtn"
|
||||
class="danger"
|
||||
class="danger mb-0"
|
||||
@click="clickDisableClasses(); close();"
|
||||
>{{ $t('optOutOfClasses') }}</span>
|
||||
</div>
|
||||
@@ -105,6 +105,11 @@
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
.btn-primary:active {
|
||||
border: 2px solid $purple-400 !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.class-badge {
|
||||
$badge-size: 32px;
|
||||
|
||||
@@ -112,7 +117,7 @@
|
||||
height: $badge-size;
|
||||
background: $white;
|
||||
box-shadow: 0 2px 2px 0 rgba($black, 0.16), 0 1px 4px 0 rgba($black, 0.12);
|
||||
border-radius: 100px;
|
||||
border-radius: 50px;
|
||||
|
||||
.svg-icon {
|
||||
width: 19px;
|
||||
@@ -121,8 +126,8 @@
|
||||
}
|
||||
|
||||
.class-explanation {
|
||||
font-size: 16px;
|
||||
margin: 1.5em auto;
|
||||
font-size: 1rem;
|
||||
margin: 24px auto;
|
||||
}
|
||||
|
||||
#classOptOutBtn {
|
||||
@@ -130,35 +135,37 @@
|
||||
}
|
||||
|
||||
.class-name {
|
||||
font-size: 24px;
|
||||
font-size: 1.5rem;
|
||||
font-weight: bold;
|
||||
margin: auto 0.33333em;
|
||||
margin: auto 5px;
|
||||
}
|
||||
|
||||
.danger {
|
||||
color: $red-50;
|
||||
margin-bottom: 0em;
|
||||
}
|
||||
|
||||
.header-purple {
|
||||
color: $purple-200;
|
||||
margin-top: 1.33333em;
|
||||
margin-bottom: 0em;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.modal-actions {
|
||||
margin: 2em auto;
|
||||
margin: 28px auto;
|
||||
}
|
||||
|
||||
.opt-out-wrapper {
|
||||
margin: 1em 0 0.5em 0;
|
||||
margin: 14px 0 7px 0;
|
||||
}
|
||||
|
||||
.selection-box {
|
||||
width: 140px;
|
||||
height: 148px;
|
||||
border-radius: 16px;
|
||||
border: solid 4px $purple-300;
|
||||
border-radius: 16px;
|
||||
bottom: -4px;
|
||||
height: 150px;
|
||||
left: -4px;
|
||||
right: -4px;
|
||||
top: -4px;
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.healer-color {
|
||||
@@ -231,14 +238,6 @@ export default {
|
||||
},
|
||||
classGear (heroClass) {
|
||||
if (heroClass === 'rogue') {
|
||||
if (this.eventName) {
|
||||
return {
|
||||
armor: `armor_special_${this.eventName}Rogue`,
|
||||
head: `head_special_${this.eventName}Rogue`,
|
||||
shield: `shield_special_${this.eventName}Rogue`,
|
||||
weapon: `weapon_special_${this.eventName}Rogue`,
|
||||
};
|
||||
}
|
||||
return {
|
||||
armor: 'armor_rogue_5',
|
||||
head: 'head_rogue_5',
|
||||
@@ -246,40 +245,24 @@ export default {
|
||||
weapon: 'weapon_rogue_6',
|
||||
};
|
||||
} if (heroClass === 'wizard') {
|
||||
if (this.eventName) {
|
||||
return {
|
||||
armor: `armor_special_${this.eventName}Mage`,
|
||||
head: `head_special_${this.eventName}Mage`,
|
||||
weapon: `weapon_special_${this.eventName}Mage`,
|
||||
};
|
||||
}
|
||||
return {
|
||||
armor: 'armor_wizard_5',
|
||||
head: 'head_wizard_5',
|
||||
weapon: 'weapon_wizard_6',
|
||||
};
|
||||
} if (heroClass === 'healer') {
|
||||
if (this.eventName) {
|
||||
return {
|
||||
armor: `armor_special_${this.eventName}Healer`,
|
||||
head: `head_special_${this.eventName}Healer`,
|
||||
shield: `shield_special_${this.eventName}Healer`,
|
||||
weapon: `weapon_special_${this.eventName}Healer`,
|
||||
};
|
||||
}
|
||||
return {
|
||||
armor: 'armor_healer_5',
|
||||
head: 'head_healer_5',
|
||||
shield: 'shield_healer_5',
|
||||
weapon: 'weapon_healer_6',
|
||||
};
|
||||
}
|
||||
if (this.eventName) {
|
||||
} if (heroClass === 'warrior') {
|
||||
return {
|
||||
armor: `armor_special_${this.eventName}Warrior`,
|
||||
head: `head_special_${this.eventName}Warrior`,
|
||||
shield: `shield_special_${this.eventName}Warrior`,
|
||||
weapon: `weapon_special_${this.eventName}Warrior`,
|
||||
armor: 'armor_warrior_5',
|
||||
head: 'head_warrior_5',
|
||||
shield: 'shield_warrior_5',
|
||||
weapon: 'weapon_warrior_6',
|
||||
};
|
||||
}
|
||||
return {
|
||||
|
||||
@@ -23,16 +23,14 @@
|
||||
{{ $t('foundNewItems') }}
|
||||
</h2>
|
||||
<div class="d-flex justify-content-center">
|
||||
<div
|
||||
<Sprite
|
||||
class="item-box ml-auto mr-3"
|
||||
:class="eggClass"
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
:image-name="eggClass"
|
||||
/>
|
||||
<Sprite
|
||||
class="item-box mr-auto"
|
||||
:class="potionClass"
|
||||
>
|
||||
</div>
|
||||
:image-name="potionClass"
|
||||
/>
|
||||
</div>
|
||||
<p
|
||||
v-once
|
||||
@@ -103,8 +101,12 @@
|
||||
|
||||
<script>
|
||||
import closeIcon from '@/assets/svg/close.svg';
|
||||
import Sprite from '@/components/ui/sprite.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Sprite,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
</div>
|
||||
<div class="inner-content">
|
||||
<div class="achievement-background d-flex align-items-center">
|
||||
<div
|
||||
<Sprite
|
||||
class="icon"
|
||||
:class="achievementClass"
|
||||
></div>
|
||||
:image-name="achievementClass"
|
||||
/>
|
||||
</div>
|
||||
<h4
|
||||
class="title"
|
||||
@@ -99,8 +99,12 @@
|
||||
import achievements from '@/../../common/script/content/achievements';
|
||||
import { mapState } from '@/libs/store';
|
||||
import svgClose from '@/assets/svg/close.svg';
|
||||
import Sprite from '@/components/ui/sprite.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Sprite,
|
||||
},
|
||||
props: ['data'],
|
||||
data () {
|
||||
return {
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
@hide="hide"
|
||||
>
|
||||
<div class="modal-body text-center">
|
||||
<div
|
||||
<Sprite
|
||||
class="quest"
|
||||
:class="`quest_${user.party.quest.completed}`"
|
||||
></div>
|
||||
:image-name="`quest_${user.party.quest.completed}`"
|
||||
/>
|
||||
<p
|
||||
v-if="questData.completion && typeof questData.completion === 'function'"
|
||||
v-html="questData.completion()"
|
||||
@@ -58,10 +58,12 @@ import percent from '@/../../common/script/libs/percent';
|
||||
import { MAX_HEALTH as maxHealth } from '@/../../common/script/constants';
|
||||
import { mapState } from '@/libs/store';
|
||||
import QuestRewards from '../shops/quests/questRewards';
|
||||
import Sprite from '../ui/sprite';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
QuestRewards,
|
||||
Sprite,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
||||