Implement new scheduling for time travelers shop

This commit is contained in:
Phillip Thelen
2024-01-31 17:27:03 +01:00
committed by Sabe Jones
parent ce796fa1d9
commit 278d9b74f9
6 changed files with 378 additions and 224 deletions

View File

@@ -6,23 +6,105 @@ import timeTravelers from '../../website/common/script/content/time-travelers';
describe('time-travelers store', () => {
let user;
let date;
beforeEach(() => {
user = generateUser();
});
describe('on january 15th', () => {
beforeEach(() => {
date = new Date('2024-01-15');
});
it('returns the correct gear', () => {
const items = timeTravelers.timeTravelerStore(user, date);
for (const [key] of Object.entries(items)) {
if (key.startsWith('20')) {
expect(key).to.match(/20[0-9]{2}(01|07)/);
}
}
});
it('removes owned sets from the time travelers store', () => {
user.items.gear.owned.head_mystery_201602 = true; // eslint-disable-line camelcase
expect(timeTravelers.timeTravelerStore(user)['201602']).to.not.exist;
expect(timeTravelers.timeTravelerStore(user)['201603']).to.exist;
user.items.gear.owned.head_mystery_201601 = true; // eslint-disable-line camelcase
const items = timeTravelers.timeTravelerStore(user, date);
expect(items['201601']).to.not.exist;
expect(items['201801']).to.exist;
expect(items['202207']).to.exist;
});
it('removes unopened mystery item sets from the time travelers store', () => {
user.purchased = {
plan: {
mysteryItems: ['head_mystery_201602'],
mysteryItems: ['head_mystery_201601'],
},
};
expect(timeTravelers.timeTravelerStore(user)['201602']).to.not.exist;
expect(timeTravelers.timeTravelerStore(user)['201603']).to.exist;
const items = timeTravelers.timeTravelerStore(user, date);
expect(items['201601']).to.not.exist;
expect(items['201607']).to.exist;
});
});
describe('on may 1st', () => {
beforeEach(() => {
date = new Date('2024-05-01');
});
it('returns the correct gear', () => {
const items = timeTravelers.timeTravelerStore(user, date);
for (const [key] of Object.entries(items)) {
if (key.startsWith('20')) {
expect(key).to.match(/20[0-9]{2}(05|11)/);
}
}
});
it('removes owned sets from the time travelers store', () => {
user.items.gear.owned.head_mystery_201705 = true; // eslint-disable-line camelcase
const items = timeTravelers.timeTravelerStore(user, date);
expect(items['201705']).to.not.exist;
expect(items['201805']).to.exist;
expect(items['202211']).to.exist;
});
it('removes unopened mystery item sets from the time travelers store', () => {
user.purchased = {
plan: {
mysteryItems: ['head_mystery_201705'],
},
};
const items = timeTravelers.timeTravelerStore(user, date);
expect(items['201705']).to.not.exist;
expect(items['201611']).to.exist;
});
});
describe('on october 21st', () => {
beforeEach(() => {
date = new Date('2024-10-21');
});
it('returns the correct gear', () => {
const items = timeTravelers.timeTravelerStore(user, date);
for (const [key] of Object.entries(items)) {
if (key.startsWith('20')) {
expect(key).to.match(/20[0-9]{2}(10|04)/);
}
}
});
it('removes owned sets from the time travelers store', () => {
user.items.gear.owned.head_mystery_201810 = true; // eslint-disable-line camelcase
user.items.gear.owned.armor_mystery_201810 = true; // eslint-disable-line camelcase
const items = timeTravelers.timeTravelerStore(user, date);
expect(items['201810']).to.not.exist;
expect(items['201910']).to.exist;
expect(items['202204']).to.exist;
});
it('removes unopened mystery item sets from the time travelers store', () => {
user.purchased = {
plan: {
mysteryItems: ['armor_mystery_201710'],
},
};
const items = timeTravelers.timeTravelerStore(user, date);
expect(items['201710']).to.not.exist;
expect(items['201604']).to.exist;
});
});
});

View File

@@ -1,18 +1,26 @@
import moment from 'moment';
function backgroundMatcher(month, oddYear) {
return function (background) {
const key = background.set.key;
function backgroundMatcher (month1, month2, oddYear) {
return function call (key) {
if (!key.startsWith('backgrounds')) return true;
const keyLength = key.length;
return parseInt(key.substring(keyLength-6, keyLength-4)) === month && parseInt(key.subtring(keyLength-2, keyLength)) % 2 === oddYear;
}
const month = parseInt(key.substring(keyLength - 6, keyLength - 4), 10);
return (month === month1 || month === month2)
&& parseInt(key.substring(keyLength - 2, keyLength), 10) % 2 === (oddYear ? 1 : 0);
};
}
function timeTravelersMatcher(month1, month2) {
return function (item) {
console.log(item, month1, month2)
return item;
}
function timeTravelersMatcher (month1, month2) {
return function call (item) {
const itemMonth = parseInt(item.substring(4, 6), 10);
return itemMonth === month1 || itemMonth === month2;
};
}
function inListMatcher (list) {
return function call (item) {
return list.indexOf(item) !== -1;
};
}
export const FIRST_RELEASE_DAY = 1;
@@ -24,13 +32,27 @@ export const MONTHLY_SCHEDULE = {
0: {
[FIRST_RELEASE_DAY]: [
{
"type": "timeTravelers",
"matcher": timeTravelersMatcher(1, 7),
}
type: 'timeTravelers',
matcher: timeTravelersMatcher(1, 7),
},
],
[SECOND_RELEASE_DAY]: [
{
type: 'backgrounds',
matcher: backgroundMatcher(1, 7, false),
},
],
[THIRD_RELEASE_DAY]: [
{
type: 'petQuests',
matcher: inListMatcher([
'ghost_stag',
'trex',
'harpy',
'sabretooth',
'dolphin',
]),
},
],
[FOURTH_RELEASE_DAY]: [
],
@@ -38,11 +60,15 @@ export const MONTHLY_SCHEDULE = {
1: {
[FIRST_RELEASE_DAY]: [
{
"type": "timeTravelers",
"matcher": timeTravelersMatcher(2, 8),
}
type: 'timeTravelers',
matcher: timeTravelersMatcher(2, 8),
},
],
[SECOND_RELEASE_DAY]: [
{
type: 'backgrounds',
matcher: backgroundMatcher(2, 8, false),
},
],
[THIRD_RELEASE_DAY]: [
],
@@ -52,11 +78,15 @@ export const MONTHLY_SCHEDULE = {
2: {
[FIRST_RELEASE_DAY]: [
{
"type": "timeTravelers",
"matcher": timeTravelersMatcher(3, 9),
}
type: 'timeTravelers',
matcher: timeTravelersMatcher(3, 9),
},
],
[SECOND_RELEASE_DAY]: [
{
type: 'backgrounds',
matcher: backgroundMatcher(3, 9, false),
},
],
[THIRD_RELEASE_DAY]: [
],
@@ -66,11 +96,15 @@ export const MONTHLY_SCHEDULE = {
3: {
[FIRST_RELEASE_DAY]: [
{
"type": "timeTravelers",
"matcher": timeTravelersMatcher(4, 10),
}
type: 'timeTravelers',
matcher: timeTravelersMatcher(4, 10),
},
],
[SECOND_RELEASE_DAY]: [
{
type: 'backgrounds',
matcher: backgroundMatcher(4, 10, false),
},
],
[THIRD_RELEASE_DAY]: [
],
@@ -80,11 +114,15 @@ export const MONTHLY_SCHEDULE = {
4: {
[FIRST_RELEASE_DAY]: [
{
"type": "timeTravelers",
"matcher": timeTravelersMatcher(5, 11),
}
type: 'timeTravelers',
matcher: timeTravelersMatcher(5, 11),
},
],
[SECOND_RELEASE_DAY]: [
{
type: 'backgrounds',
matcher: backgroundMatcher(5, 11, false),
},
],
[THIRD_RELEASE_DAY]: [
],
@@ -94,11 +132,15 @@ export const MONTHLY_SCHEDULE = {
5: {
[FIRST_RELEASE_DAY]: [
{
"type": "timeTravelers",
"matcher": timeTravelersMatcher(6, 12),
}
type: 'timeTravelers',
matcher: timeTravelersMatcher(6, 12),
},
],
[SECOND_RELEASE_DAY]: [
{
type: 'backgrounds',
matcher: backgroundMatcher(6, 12, false),
},
],
[THIRD_RELEASE_DAY]: [
],
@@ -108,11 +150,15 @@ export const MONTHLY_SCHEDULE = {
6: {
[FIRST_RELEASE_DAY]: [
{
"type": "timeTravelers",
"matcher": timeTravelersMatcher(7, 1),
}
type: 'timeTravelers',
matcher: timeTravelersMatcher(7, 1),
},
],
[SECOND_RELEASE_DAY]: [
{
type: 'backgrounds',
matcher: backgroundMatcher(7, 1, true),
},
],
[THIRD_RELEASE_DAY]: [
],
@@ -122,11 +168,15 @@ export const MONTHLY_SCHEDULE = {
7: {
[FIRST_RELEASE_DAY]: [
{
"type": "timeTravelers",
"matcher": timeTravelersMatcher(8, 2),
}
type: 'timeTravelers',
matcher: timeTravelersMatcher(8, 2),
},
],
[SECOND_RELEASE_DAY]: [
{
type: 'backgrounds',
matcher: backgroundMatcher(8, 2, true),
},
],
[THIRD_RELEASE_DAY]: [
],
@@ -136,11 +186,15 @@ export const MONTHLY_SCHEDULE = {
8: {
[FIRST_RELEASE_DAY]: [
{
"type": "timeTravelers",
"matcher": timeTravelersMatcher(9, 3),
}
type: 'timeTravelers',
matcher: timeTravelersMatcher(9, 3),
},
],
[SECOND_RELEASE_DAY]: [
{
type: 'backgrounds',
matcher: backgroundMatcher(9, 3, true),
},
],
[THIRD_RELEASE_DAY]: [
],
@@ -150,11 +204,15 @@ export const MONTHLY_SCHEDULE = {
9: {
[FIRST_RELEASE_DAY]: [
{
"type": "timeTravelers",
"matcher": timeTravelersMatcher(10, 4),
}
type: 'timeTravelers',
matcher: timeTravelersMatcher(10, 4),
},
],
[SECOND_RELEASE_DAY]: [
{
type: 'backgrounds',
matcher: backgroundMatcher(10, 4, true),
},
],
[THIRD_RELEASE_DAY]: [
],
@@ -164,11 +222,15 @@ export const MONTHLY_SCHEDULE = {
10: {
[FIRST_RELEASE_DAY]: [
{
"type": "timeTravelers",
"matcher": timeTravelersMatcher(11, 5),
}
type: 'timeTravelers',
matcher: timeTravelersMatcher(11, 5),
},
],
[SECOND_RELEASE_DAY]: [
{
type: 'backgrounds',
matcher: backgroundMatcher(11, 5, true),
},
],
[THIRD_RELEASE_DAY]: [
],
@@ -178,11 +240,15 @@ export const MONTHLY_SCHEDULE = {
11: {
[FIRST_RELEASE_DAY]: [
{
"type": "timeTravelers",
"matcher": timeTravelersMatcher(12, 6),
}
type: 'timeTravelers',
matcher: timeTravelersMatcher(12, 6),
},
],
[SECOND_RELEASE_DAY]: [
{
type: 'backgrounds',
matcher: backgroundMatcher(12, 6, true),
},
],
[THIRD_RELEASE_DAY]: [
],
@@ -199,7 +265,7 @@ export const GALA_SCHEDULE = {
3: [],
};
export function assembleScheduledMatchers(date) {
export function assembleScheduledMatchers (date) {
const items = [];
const month = date instanceof moment ? date.month() : date.getMonth();
const todayDay = date instanceof moment ? date.date() : date.getDate();
@@ -219,6 +285,6 @@ export function assembleScheduledMatchers(date) {
if (todayDay >= GALA_SWITCHOVER_DAY) {
galaMonth += 1;
}
items.push(...GALA_SCHEDULE[parseInt((galaCount / 12) * galaMonth)]);
items.push(...GALA_SCHEDULE[parseInt((galaCount / 12) * galaMonth, 10)]);
return items;
}

View File

@@ -33,6 +33,8 @@ import gemsBlock from './gems';
import faq from './faq';
import timeTravelers from './time-travelers';
import { assembleScheduledMatchers } from './constants/schedule';
import loginIncentives from './loginIncentives';
import officialPinnedItems from './officialPinnedItems';
@@ -728,4 +730,6 @@ api.faq = faq;
api.loginIncentives = loginIncentives(api);
api.assembleScheduledMatchers = assembleScheduledMatchers;
export default api;

View File

@@ -7,6 +7,7 @@ import moment from 'moment';
import mysterySets from './mystery-sets';
import gear from './gear';
import { assembleScheduledMatchers } from './constants/schedule';
const mystery = mysterySets;
@@ -17,7 +18,8 @@ each(mystery, (v, k) => {
if (v.items.length === 0) delete mystery[k];
});
const timeTravelerStore = user => {
const timeTravelerStore = (user, date) => {
const availabilityMatchers = assembleScheduledMatchers(date).filter(matcher => matcher.type === 'timeTravelers').map(matcher => matcher.matcher);
let ownedKeys;
const { owned } = user.items.gear;
const { mysteryItems } = user.purchased.plan;
@@ -26,13 +28,13 @@ const timeTravelerStore = user => {
ownedKeys = union(ownedKeys, unopenedGifts);
return reduce(mystery, (m, v, k) => {
if (
k === 'wondercon'
|| ownedKeys.indexOf(v.items[0].key) !== -1
|| (moment(k).add(1, 'months').isAfter() && moment(k).isBefore('3000-01-01'))
k !== 'wondercon'
&& ownedKeys.indexOf(v.items[0].key) === -1
&& (moment(k).isAfter('3000-01-01')
|| availabilityMatchers.map(matcher => matcher(k)).every(matcher => matcher === true))
) {
return m;
}
m[k] = v;
}
return m;
}, {});
};

View File

@@ -369,7 +369,7 @@ shops.getTimeTravelersCategories = function getTimeTravelersCategories (user, la
}
}
const sets = content.timeTravelerStore(user);
const sets = content.timeTravelerStore(user, new Date());
for (const setKey of Object.keys(sets)) {
const set = sets[setKey];
const category = {

View File

@@ -20,7 +20,7 @@ export default async function buyMysterySet (user, req = {}, analytics) {
throw new NotAuthorized(i18n.t('notEnoughHourglasses', req.language));
}
const ref = content.timeTravelerStore(user);
const ref = content.timeTravelerStore(user, new Date());
const mysterySet = ref ? ref[key] : undefined;
if (!mysterySet) {