mirror of
https://github.com/MetaFam/TheGame.git
synced 2026-04-24 03:00:09 -04:00
* Remove connect to progress if the network is not mainnet
* Move xpHelpers to the utils
* Add tests to the utils package
* Add xpHelpers test
* Add convertToRoman util function
* Display current season label dynamically
* Add onboarding text if player does not have xp
* Remove ConnectToProgress import
* Add connect to progress if the network is not mainnet
* Show edit button if network is not main
* Refactor xp helper season start
* displaying modal when chain change is needed 🛬
* using Unicode Roman numerals Ⅲ
* slight formatting fixes 🗯
This commit is contained in:
@@ -2,6 +2,7 @@ import {
|
||||
Constants,
|
||||
fetch,
|
||||
getLatestEthAddress,
|
||||
getNumWeeksInSeason,
|
||||
isNotNullOrUndefined,
|
||||
} from '@metafam/utils';
|
||||
import bluebird from 'bluebird';
|
||||
@@ -15,7 +16,6 @@ import {
|
||||
import { client } from '../../../lib/hasuraClient';
|
||||
import { computeRank } from '../../../lib/rankHelpers';
|
||||
import { ledgerManager } from '../../../lib/sourcecredLedger';
|
||||
import { getNumWeeksInSeason } from '../../../lib/xpHelpers';
|
||||
|
||||
const VALID_ACCOUNT_TYPES: Array<AccountType_Enum> = [
|
||||
AccountType_Enum.Ethereum,
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
export const getNumWeeksInSeason = (currentDate: Date = new Date()): number => {
|
||||
const currentYear = currentDate.getFullYear();
|
||||
|
||||
const lastYear = currentDate.getFullYear() - 1;
|
||||
|
||||
const seasons = [
|
||||
new Date(Date.parse(`${lastYear}-12-21T00:00:00+00:00`)), // 21 Dec last year
|
||||
new Date(Date.parse(`${currentYear}-03-20T00:00:00+00:00`)), // 20 Mar this year
|
||||
new Date(Date.parse(`${currentYear}-06-21T00:00:00+00:00`)), // 21 June this year
|
||||
new Date(Date.parse(`${currentYear}-09-22T00:00:00+00:00`)), // 22 Sept this year
|
||||
new Date(Date.parse(`${currentYear}-12-21T00:00:00+00:00`)), // 21 Dec this year
|
||||
];
|
||||
|
||||
const currentSeason = seasons.reduce(
|
||||
(t, a) => (a.getTime() < currentDate.getTime() ? a : t),
|
||||
new Date('1970-01-01T00:00:00+00:00'),
|
||||
);
|
||||
|
||||
return Math.ceil(
|
||||
(currentDate.getTime() - currentSeason.getTime()) /
|
||||
(1000 * 60 * 60 * 24 * 7),
|
||||
);
|
||||
};
|
||||
3
packages/utils/jest.config.js
Normal file
3
packages/utils/jest.config.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
testEnvironment: 'node',
|
||||
};
|
||||
@@ -10,7 +10,8 @@
|
||||
"build": "tsc -b",
|
||||
"dev": "yarn build --watch",
|
||||
"typecheck": "yarn build",
|
||||
"precommit": "yarn lint-staged"
|
||||
"precommit": "yarn lint-staged",
|
||||
"test": "tsdx test --passWithNoTests"
|
||||
},
|
||||
"dependencies": {
|
||||
"@datamodels/identity-profile-basic": "0.1.2",
|
||||
|
||||
@@ -16,6 +16,7 @@ export * as numbers from './numbers';
|
||||
export * from './promiseHelpers';
|
||||
export * from './rankHelpers';
|
||||
export * from './sourceCredHelpers';
|
||||
export * from './xpHelpers';
|
||||
|
||||
export { uuidv4 as generateUUID };
|
||||
export { extendedProfileModel };
|
||||
|
||||
65
packages/utils/src/xpHelpers.ts
Normal file
65
packages/utils/src/xpHelpers.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
export const getNumWeeksInSeason = (currentDate: Date = new Date()): number => {
|
||||
const currentYear = currentDate.getFullYear();
|
||||
|
||||
const lastYear = currentDate.getFullYear() - 1;
|
||||
|
||||
const seasons = [
|
||||
new Date(Date.parse(`${lastYear}-12-21T00:00:00+00:00`)), // 21 Dec last year
|
||||
new Date(Date.parse(`${currentYear}-03-20T00:00:00+00:00`)), // 20 Mar this year
|
||||
new Date(Date.parse(`${currentYear}-06-21T00:00:00+00:00`)), // 21 June this year
|
||||
new Date(Date.parse(`${currentYear}-09-22T00:00:00+00:00`)), // 22 Sept this year
|
||||
new Date(Date.parse(`${currentYear}-12-21T00:00:00+00:00`)), // 21 Dec this year
|
||||
];
|
||||
|
||||
const currentSeason = seasons.reduce(
|
||||
(t, a) => (a.getTime() < currentDate.getTime() ? a : t),
|
||||
new Date('1970-01-01T00:00:00+00:00'),
|
||||
);
|
||||
|
||||
return Math.ceil(
|
||||
(currentDate.getTime() - currentSeason.getTime()) /
|
||||
(1000 * 60 * 60 * 24 * 7),
|
||||
);
|
||||
};
|
||||
|
||||
export const getSeasonNum = (currentDate: Date = new Date()): number => {
|
||||
const GAME_STARTED = new Date('2020-12-21');
|
||||
|
||||
const seasons = [];
|
||||
|
||||
let activeDate = new Date(GAME_STARTED);
|
||||
let activeIndex = 4;
|
||||
|
||||
const boundaries = [
|
||||
{ month: 3, day: 19 },
|
||||
{ month: 6, day: 20 },
|
||||
{ month: 9, day: 22 },
|
||||
{ month: 12, day: 20 },
|
||||
];
|
||||
|
||||
const leapYear = activeDate.getFullYear() % 4 === 0;
|
||||
|
||||
const SEASON_START = boundaries.map(
|
||||
({ month, day }) =>
|
||||
new Date(activeDate.getFullYear(), month - 1, day + (leapYear ? 0 : 1)),
|
||||
);
|
||||
|
||||
while (currentDate > activeDate) {
|
||||
seasons.push(activeDate);
|
||||
|
||||
if (activeIndex === SEASON_START.length) {
|
||||
const newDate = new Date(activeDate).setFullYear(
|
||||
activeDate.getFullYear() + 1,
|
||||
);
|
||||
activeDate = new Date(newDate);
|
||||
activeIndex = 0;
|
||||
}
|
||||
|
||||
const nextDate = SEASON_START[activeIndex];
|
||||
nextDate.setFullYear(activeDate.getFullYear());
|
||||
activeDate = new Date(nextDate);
|
||||
activeIndex += 1;
|
||||
}
|
||||
|
||||
return seasons.length;
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getNumWeeksInSeason } from '../../src/lib/xpHelpers';
|
||||
import { getNumWeeksInSeason, getSeasonNum } from '../../src/xpHelpers';
|
||||
|
||||
describe('getNumWeeksInSeason', () => {
|
||||
const currentDate = new Date();
|
||||
@@ -26,3 +26,15 @@ describe('getNumWeeksInSeason', () => {
|
||||
expect(getNumWeeksInSeason(Jun21st)).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSeasonNum', () => {
|
||||
it('Dec 22 should be season 1', () => {
|
||||
const Dec22nd = new Date(Date.parse(`2020-12-22T00:01:00+00:00`));
|
||||
expect(getSeasonNum(Dec22nd)).toBe(1);
|
||||
});
|
||||
|
||||
it('April 1st 2022 should be season 6', () => {
|
||||
const Apr1st = new Date(Date.parse(`2022-04-01T00:01:00+00:00`));
|
||||
expect(getSeasonNum(Apr1st)).toBe(6);
|
||||
});
|
||||
});
|
||||
@@ -25,7 +25,12 @@ export const MetaGameLogo = () => (
|
||||
export const ConnectToProgress: React.FC<{
|
||||
showNote?: boolean;
|
||||
showSwitchButton?: boolean;
|
||||
}> = ({ showNote = false, showSwitchButton = true }) => {
|
||||
header?: string;
|
||||
}> = ({
|
||||
showNote = false,
|
||||
showSwitchButton = true,
|
||||
header = 'Welcome to MetaGame!',
|
||||
}) => {
|
||||
const { connect, connecting, connected, chainId } = useWeb3();
|
||||
const [open, { toggle }] = useBoolean();
|
||||
const { fetching } = useUser();
|
||||
@@ -35,7 +40,7 @@ export const ConnectToProgress: React.FC<{
|
||||
return (
|
||||
<Stack color="white" spacing={8} w="100%" maxW="30rem">
|
||||
<MetaGameLogo />
|
||||
<MetaHeading> Welcome to MetaGame! </MetaHeading>
|
||||
{header && header !== '' && <MetaHeading>{header}</MetaHeading>}
|
||||
<Text fontSize="md" w="100%" textAlign="center">
|
||||
Please switch to <SwitchNetworkButton chainId="0x1" /> to progress
|
||||
</Text>
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
Box,
|
||||
Button,
|
||||
ButtonGroup,
|
||||
Link,
|
||||
MetaTag,
|
||||
Stat,
|
||||
StatArrow,
|
||||
@@ -33,7 +34,14 @@ export const XP = (): React.ReactElement => {
|
||||
if (xpStats == null) {
|
||||
return (
|
||||
<Text fontStyle="italic" textAlign="center" p={4} w="100%">
|
||||
Unknown
|
||||
If you want your XP stats to appear, you gotta earn some XP first! Go{' '}
|
||||
<Link
|
||||
href="https://meta-game.notion.site/Welcome-to-MetaGame-349d9b6434d543b48539bccabf10b60a"
|
||||
target="_tab"
|
||||
>
|
||||
here
|
||||
</Link>{' '}
|
||||
& join the onboarding call
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -458,7 +458,31 @@ export const EditProfileModal: React.FC<ProfileEditorProps> = ({
|
||||
};
|
||||
|
||||
if (chainId !== '0x1') {
|
||||
return <ConnectToProgress />;
|
||||
return (
|
||||
<Modal {...{ isOpen, onClose }}>
|
||||
<ModalOverlay />
|
||||
<ModalContent
|
||||
maxW={['100%', 'min(80%, 60rem)']}
|
||||
backgroundImage={`url(${BackgroundImage})`}
|
||||
bgSize="cover"
|
||||
bgAttachment="fixed"
|
||||
p={[0, 8, 12]}
|
||||
>
|
||||
<ModalHeader>
|
||||
<MetaHeading color="white">Wrong Chain</MetaHeading>
|
||||
</ModalHeader>
|
||||
<ModalCloseButton
|
||||
color="pinkShadeOne"
|
||||
size="xl"
|
||||
p={{ base: 1, sm: 4 }}
|
||||
_focus={{ boxShadow: 'none' }}
|
||||
/>
|
||||
<ModalBody p={[0, 2]} alignSelf="center">
|
||||
<ConnectToProgress header="" />
|
||||
</ModalBody>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
Wrap,
|
||||
WrapItem,
|
||||
} from '@metafam/ds';
|
||||
import { Maybe } from '@metafam/utils';
|
||||
import { getSeasonNum, Maybe } from '@metafam/utils';
|
||||
import { PlayerAvatar } from 'components/Player/PlayerAvatar';
|
||||
import { PlayerContacts } from 'components/Player/PlayerContacts';
|
||||
import { PlayerTileMemberships } from 'components/Player/PlayerTileMemberships';
|
||||
@@ -25,6 +25,7 @@ import { Player, Skill } from 'graphql/autogen/types';
|
||||
import NextLink from 'next/link';
|
||||
import React, { useMemo } from 'react';
|
||||
import { FaGlobe } from 'react-icons/fa';
|
||||
import { convertToRoman } from 'utils/formatHelpers';
|
||||
import {
|
||||
getPlayerBanner,
|
||||
getPlayerDescription,
|
||||
@@ -104,7 +105,7 @@ export const PlayerTile: React.FC<Props> = ({
|
||||
{showSeasonalXP && (
|
||||
<WrapItem>
|
||||
<MetaTag size="md">
|
||||
SEASON Ⅵ XP:{' '}
|
||||
SEASON {convertToRoman(getSeasonNum())} XP:{' '}
|
||||
{Math.floor(player.seasonXP).toLocaleString()}
|
||||
</MetaTag>
|
||||
</WrapItem>
|
||||
|
||||
@@ -46,12 +46,13 @@ type DisplayComponentProps = {
|
||||
|
||||
export const PlayerHero: React.FC<HeroProps> = ({ player, editing }) => {
|
||||
const { user } = useUser();
|
||||
|
||||
const isOwnProfile = user ? user.id === player?.id : null;
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
|
||||
// 9tails.eth: As there is no current way of editing Profile Accounts,
|
||||
// and the MWW integratino happens on the EditProfileModal, to avoid
|
||||
// adding a new column to the table just to do the followig, I decided
|
||||
// adding a new column to the table just to do the following, I decided
|
||||
// to this this cast as any to use the information from the form and
|
||||
// don't do bigger changes on the data structure just because of it
|
||||
const profileFields = useProfileField({
|
||||
|
||||
@@ -65,8 +65,13 @@ const fetchOpenSeaData = async (
|
||||
const res = await fetch(
|
||||
`/api/opensea?owner=${owner}&offset=${offset}&limit=${limit}`,
|
||||
);
|
||||
const { assets, error } = await res.json();
|
||||
if (error) throw new Error(error);
|
||||
const body = await res.text();
|
||||
const { assets, error } = JSON.parse(body);
|
||||
if (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error({ error, body });
|
||||
throw new Error(error);
|
||||
}
|
||||
if (!assets) throw new Error(`Received ${assets} assets`);
|
||||
return assets;
|
||||
};
|
||||
|
||||
63
packages/web/utils/formatHelpers.ts
Normal file
63
packages/web/utils/formatHelpers.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
export const convertToRoman = (_num: number): string => {
|
||||
let num = _num;
|
||||
|
||||
type RomanOptions = {
|
||||
[key: string]: number;
|
||||
};
|
||||
|
||||
const romans: RomanOptions = {
|
||||
ↈ: 100_000,
|
||||
ↇ: 50_000,
|
||||
ↂ: 10_000,
|
||||
ↁ: 5_000,
|
||||
Ⅿ: 1_000,
|
||||
ⅭⅯ: 900,
|
||||
Ⅾ: 500,
|
||||
ⅭⅮ: 400,
|
||||
Ⅽ: 100,
|
||||
ⅩⅭ: 90,
|
||||
Ⅼ: 50,
|
||||
ⅩⅬ: 40,
|
||||
Ⅹ: 10,
|
||||
Ⅸ: 9,
|
||||
Ⅴ: 5,
|
||||
Ⅳ: 4,
|
||||
Ⅰ: 1,
|
||||
};
|
||||
const smallRomans = [
|
||||
'Ⅰ',
|
||||
'Ⅱ',
|
||||
'Ⅲ',
|
||||
'Ⅳ',
|
||||
'Ⅴ',
|
||||
'Ⅵ',
|
||||
'Ⅶ',
|
||||
'Ⅷ',
|
||||
'Ⅸ',
|
||||
'Ⅹ',
|
||||
'Ⅺ',
|
||||
'Ⅻ',
|
||||
'ⅩⅢ',
|
||||
'ⅩⅣ',
|
||||
'ⅩⅤ',
|
||||
'ⅩⅥ',
|
||||
'ⅩⅦ',
|
||||
'ⅩⅡⅩ',
|
||||
'ⅩⅠⅩ',
|
||||
];
|
||||
|
||||
if (num < smallRomans.length) {
|
||||
return smallRomans[num - 1];
|
||||
}
|
||||
|
||||
let str = '';
|
||||
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const i of Object.keys(romans)) {
|
||||
const q = Math.floor(num / romans[i]);
|
||||
num -= q * romans[i];
|
||||
str += i.repeat(q);
|
||||
}
|
||||
|
||||
return str;
|
||||
};
|
||||
Reference in New Issue
Block a user