Files
TheGame/packages/web/lib/hooks/useUserXP.ts
δυς 81883f940e Miscellaneous changes pulled from #1078 (#1115)
​#1078 is at about 4,000 lines changed and includes both code implementing features and unrelated functional and stylistic changes. This set of changes is about ⅓ of the total and should be largely independent.

These changes include:

* have Dependabot ignore `patch` version changes
* switch the cache invalidation Hasura action to asynchronous
* add a uniqueness constraint on the combination of player and skill ids
* print a comprehensible error message in the db seeding script on network errors
* add a mutex on the account creation process & allow it to happen only once *(subsequent runs were failing b/c of the uniqueness constraint on the ETH address & returning `null` (closes #1098))
* adds some more profile editing related types
* renames `HighLow7dType` to `HighLowType`
* refactors the `ColorBar` component to include links to a color explanation
* replaces `fake-tag`'s `gql` string identifier with the dependency-free `/* GraphQL */`
* rename `lib/hooks/useUserXp.ts` to `useUserXP.ts`
* fixed some typings to remove `any`s
* bumped some library versions & fixed the version numbers of some others
2022-02-08 06:01:06 -05:00

83 lines
2.3 KiB
TypeScript

import { Constants } from '@metafam/utils';
import { ethers } from 'ethers';
import { useEffect, useState } from 'react';
import { SCAccount, SCAccountsData } from 'sourcecred';
interface XPProps {
userTotalXP: number;
variationThisWeek: number;
variationLastWeek: number;
thisWeekXP: number;
lastWeekXP: number;
userWeeklyCred: number[];
}
export const useUserXP = (userAddress: string): XPProps | null => {
const [xpDataObj, setXPDataObj] = useState<XPProps | null>(null);
useEffect(() => {
if (ethers.utils.isAddress(userAddress))
getXP(userAddress).then((res) => {
if (res) setXPDataObj(res);
});
}, [userAddress]);
return xpDataObj;
};
const getXP = async (userAddress: string): Promise<XPProps | null> => {
try {
const accountsData: SCAccountsData = await (
await fetch(Constants.SC_ACCOUNTS_FILE)
).json();
const scAccount = await accountsData.accounts.find((account) =>
accountFilter(account, userAddress),
);
if (!scAccount) return null;
const userTotalXP = roundToTwoDecimal(scAccount.totalCred);
const numWeeks = scAccount.cred.length;
const userWeeklyCred = scAccount.cred;
let variationThisWeek = calculateVariation(
userWeeklyCred[numWeeks - 1],
userWeeklyCred[numWeeks - 2],
);
let variationLastWeek = calculateVariation(
userWeeklyCred[numWeeks - 2],
userWeeklyCred[numWeeks - 3],
);
const thisWeekXP = roundToTwoDecimal(userWeeklyCred[numWeeks - 1]);
const lastWeekXP = roundToTwoDecimal(userWeeklyCred[numWeeks - 2]);
variationThisWeek = roundToTwoDecimal(variationThisWeek);
variationLastWeek = roundToTwoDecimal(variationLastWeek);
return {
userTotalXP,
variationThisWeek,
variationLastWeek,
thisWeekXP,
lastWeekXP,
userWeeklyCred,
};
} catch (err: unknown) {
// throw new Error(err);
return null;
}
};
const accountFilter = (a: SCAccount, userAddress: string) => {
const { account } = a;
const acc = account.identity.aliases.find(
(alias) => alias.description.toLowerCase() === userAddress.toLowerCase(),
);
return !!acc;
};
const calculateVariation = (first: number, second: number) =>
(100 * (first - second)) / second;
const roundToTwoDecimal = (num: number): number => Math.round(num * 100) / 100;