feat : add profile page
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
export const MAX_LEVEL = 200;
|
||||
|
||||
export type LevelProgress = {
|
||||
level: number;
|
||||
totalXp: string;
|
||||
xpIntoLevel: string;
|
||||
xpRequired: string;
|
||||
xpToNextLevel: string;
|
||||
percentage: number;
|
||||
isMaxLevel: boolean;
|
||||
};
|
||||
|
||||
function asNonNegativeBigInt(value: string) {
|
||||
try {
|
||||
const parsed = BigInt(value);
|
||||
return parsed > BigInt(0) ? parsed : BigInt(0);
|
||||
} catch {
|
||||
return BigInt(0);
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeLevel(level: number) {
|
||||
if (!Number.isFinite(level)) return 0;
|
||||
return Math.min(MAX_LEVEL, Math.max(0, Math.trunc(level)));
|
||||
}
|
||||
|
||||
/** XP needed to advance from level n to n + 1. Levels 200+ use the level-199 cap. */
|
||||
export function xpRequiredForLevel(level: number) {
|
||||
const n = BigInt(Math.min(MAX_LEVEL - 1, normalizeLevel(level)));
|
||||
return BigInt(500)
|
||||
+ (BigInt(100) * n)
|
||||
+ (BigInt(25) * n * (n + BigInt(1))) / BigInt(2);
|
||||
}
|
||||
|
||||
/** Cumulative XP needed to reach a level from level 0. */
|
||||
export function totalXpForLevel(level: number) {
|
||||
const targetLevel = normalizeLevel(level);
|
||||
let total = BigInt(0);
|
||||
|
||||
for (let currentLevel = 0; currentLevel < targetLevel; currentLevel += 1) {
|
||||
total += xpRequiredForLevel(currentLevel);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
export function buildLevelProgress(level: number, rawTotalXp: string): LevelProgress {
|
||||
const normalizedLevel = normalizeLevel(level);
|
||||
const totalXp = asNonNegativeBigInt(rawTotalXp);
|
||||
const required = xpRequiredForLevel(normalizedLevel);
|
||||
const levelStart = totalXpForLevel(normalizedLevel);
|
||||
const unboundedProgress = totalXp > levelStart
|
||||
? totalXp - levelStart
|
||||
: BigInt(0);
|
||||
const xpIntoLevel = unboundedProgress > required ? required : unboundedProgress;
|
||||
const basisPoints = required === BigInt(0)
|
||||
? BigInt(0)
|
||||
: (xpIntoLevel * BigInt(10_000)) / required;
|
||||
|
||||
return {
|
||||
level: normalizedLevel,
|
||||
totalXp: totalXp.toString(),
|
||||
xpIntoLevel: xpIntoLevel.toString(),
|
||||
xpRequired: required.toString(),
|
||||
xpToNextLevel: (required - xpIntoLevel).toString(),
|
||||
percentage: Number(basisPoints) / 100,
|
||||
isMaxLevel: normalizedLevel >= MAX_LEVEL,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user