manage and cleanup some types
This commit is contained in:
parent
c7766aeda3
commit
1393df6fd0
9 changed files with 175 additions and 141 deletions
6
interfaces/APIError.ts
Normal file
6
interfaces/APIError.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
export default interface APIError {
|
||||
error: {
|
||||
message: string;
|
||||
code: number;
|
||||
};
|
||||
}
|
5
interfaces/UserAsset.ts
Normal file
5
interfaces/UserAsset.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
export default interface UserAsset {
|
||||
name: string;
|
||||
count: number;
|
||||
provider: "7tv" | "bttv" | "ffz" | "twitch";
|
||||
}
|
5
interfaces/UserBadge.ts
Normal file
5
interfaces/UserBadge.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
export default interface UserBadge {
|
||||
name: string;
|
||||
color: string;
|
||||
priority: number;
|
||||
}
|
12
interfaces/UserFakeDataEntry.ts
Normal file
12
interfaces/UserFakeDataEntry.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import UserAsset from "./UserAsset";
|
||||
import UserBadge from "./UserBadge";
|
||||
|
||||
export default interface UserFakeDataEntry {
|
||||
id: number;
|
||||
name: string;
|
||||
points: number;
|
||||
daily_change: number;
|
||||
daily_change_percent: number;
|
||||
assets: UserAsset[];
|
||||
badges: UserBadge[];
|
||||
}
|
5
interfaces/UserFakeDataJSON.ts
Normal file
5
interfaces/UserFakeDataJSON.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import UserJSONEntry from "./UserJSONEntry";
|
||||
|
||||
export default interface UserFakeDataJSON {
|
||||
data: UserJSONEntry[];
|
||||
}
|
8
interfaces/UserJSONEntry.ts
Normal file
8
interfaces/UserJSONEntry.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import UserFakeDataEntry from "./UserFakeDataEntry";
|
||||
|
||||
export default interface UserJSONEntry extends UserFakeDataEntry {
|
||||
net_worth: number;
|
||||
shares: number;
|
||||
avatar_url: string;
|
||||
rank: number;
|
||||
}
|
|
@ -1,4 +1,7 @@
|
|||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import UserBadge from "../../interfaces/UserBadge";
|
||||
import UserFakeDataEntry from "../../interfaces/UserFakeDataEntry";
|
||||
import UserJSONEntry from "../../interfaces/UserJSONEntry";
|
||||
import { createRedisInstance } from "../../misc/redis";
|
||||
import { getUserByName } from "../../misc/TwitchAPI";
|
||||
import { fakePrices } from "./fakePrices";
|
||||
|
@ -23,43 +26,14 @@ export default async function handler(
|
|||
return;
|
||||
}
|
||||
|
||||
let data = fakeData;
|
||||
// calculate all net worths
|
||||
data = data.map((user) => {
|
||||
return {
|
||||
...user,
|
||||
net_worth:
|
||||
user.points +
|
||||
user.assets.reduce(
|
||||
(a, b) => a + b.count * (fakePrices[b.name] ?? 0),
|
||||
0
|
||||
),
|
||||
};
|
||||
});
|
||||
// calculate ranking based on net worth
|
||||
data = data.sort((a, b) => (b.net_worth ?? 0) - (a.net_worth ?? 0));
|
||||
data = data.map((user, i) => {
|
||||
return {
|
||||
...user,
|
||||
rank: i + 1,
|
||||
// calculate total assets held (shares)
|
||||
shares: user.assets.reduce((a, b) => a + b.count, 0),
|
||||
// sort users badges by priority
|
||||
badges: (user.badges ?? []).sort((a, b) => b.priority - a.priority ?? 0),
|
||||
// sort users assets by total value
|
||||
assets: user.assets.sort(
|
||||
(a, b) =>
|
||||
(fakePrices[b.name] ?? 0) * b.count -
|
||||
(fakePrices[a.name] ?? 0) * a.count
|
||||
),
|
||||
};
|
||||
});
|
||||
|
||||
let userJSON: UserJSONEntry[];
|
||||
let userList: UserFakeDataEntry[] = fakeData;
|
||||
let avatarURL = "/img/logo.webp"; // default avatar
|
||||
// if username is specified, only return that user
|
||||
if (username) {
|
||||
// if user does not exist, return error
|
||||
data = data.filter((u) => u.name === username);
|
||||
if (data.length === 0) {
|
||||
// filter for user, add required types
|
||||
userList = userList.filter((u) => u.name === username);
|
||||
if (userList.length === 0) {
|
||||
res
|
||||
.status(404)
|
||||
.json({ error: { message: "User not found", code: 20000 } });
|
||||
|
@ -80,92 +54,95 @@ export default async function handler(
|
|||
// temp who cares
|
||||
twitchData.data[0] = {};
|
||||
twitchData.data[0].profile_image_url = "/img/logo.webp";
|
||||
} else {
|
||||
avatarURL = twitchData.data[0].profile_image_url;
|
||||
}
|
||||
// add users profile picture url
|
||||
data = data.map((u) => {
|
||||
}
|
||||
|
||||
userJSON = userList.map((user) => {
|
||||
return {
|
||||
...u,
|
||||
avatar_url: twitchData.data[0].profile_image_url ?? "",
|
||||
...user,
|
||||
// calculate total assets held (shares)
|
||||
shares: user.assets.reduce((a, b) => a + b.count, 0),
|
||||
// sort users badges by priority
|
||||
badges: (user.badges ?? []).sort((a, b) => b.priority - a.priority ?? 0),
|
||||
avatar_url: avatarURL,
|
||||
rank: 0,
|
||||
// sort users assets by total value
|
||||
assets: user.assets.sort(
|
||||
(a, b) =>
|
||||
(fakePrices[b.name] ?? 0) * b.count -
|
||||
(fakePrices[a.name] ?? 0) * a.count
|
||||
),
|
||||
// calculate net worth
|
||||
net_worth:
|
||||
user.points +
|
||||
user.assets.reduce(
|
||||
(a, b) => a + b.count * (fakePrices[b.name] ?? 0),
|
||||
0
|
||||
),
|
||||
};
|
||||
});
|
||||
res.status(200).json({ data: data[0] });
|
||||
return;
|
||||
}
|
||||
// calculate ranking based on net worth
|
||||
userJSON = userJSON.sort((a, b) => (b.net_worth ?? 0) - (a.net_worth ?? 0));
|
||||
userJSON = userJSON.map((u, i) => {
|
||||
return {
|
||||
...u,
|
||||
rank: i + 1,
|
||||
};
|
||||
});
|
||||
|
||||
if (sortBy) {
|
||||
if (sortBy === "daily_change") {
|
||||
data = data.sort((a, b) => b.daily_change - a.daily_change);
|
||||
userJSON = userJSON.sort((a, b) => b.daily_change - a.daily_change);
|
||||
} else if (sortBy === "daily_change_percent") {
|
||||
data = data.sort(
|
||||
userJSON = userJSON.sort(
|
||||
(a, b) => b.daily_change_percent - a.daily_change_percent
|
||||
);
|
||||
} else if (sortBy === "shares") {
|
||||
data = data.sort((a, b) => (b.shares ?? 0) - (a.shares ?? 0));
|
||||
userJSON = userJSON.sort((a, b) => (b.shares ?? 0) - (a.shares ?? 0));
|
||||
} else if (sortBy === "points") {
|
||||
data = data.sort((a, b) => b.points - a.points);
|
||||
userJSON = userJSON.sort((a, b) => b.points - a.points);
|
||||
} else if (sortBy === "name") {
|
||||
data = data.sort((a, b) => a.name.localeCompare(b.name));
|
||||
userJSON = userJSON.sort((a, b) => a.name.localeCompare(b.name));
|
||||
}
|
||||
if (sortAsc === "true") {
|
||||
// slow but only needed for temporary fake data anyway
|
||||
data = data.reverse();
|
||||
userJSON = userJSON.reverse();
|
||||
}
|
||||
}
|
||||
// fake loading time
|
||||
await new Promise((resolve) =>
|
||||
setTimeout(resolve, 250 + Math.random() * 1000)
|
||||
);
|
||||
res.status(200).json({ data: data });
|
||||
res.status(200).json({ data: userJSON });
|
||||
}
|
||||
|
||||
interface asset {
|
||||
name: string;
|
||||
count: number;
|
||||
provider: "7tv" | "bttv" | "ffz" | "twitch";
|
||||
}
|
||||
interface fakeDataEntry {
|
||||
id: number;
|
||||
name: string;
|
||||
points: number;
|
||||
daily_change: number;
|
||||
daily_change_percent: number;
|
||||
assets: asset[];
|
||||
net_worth?: number;
|
||||
shares?: number;
|
||||
avatar_url?: string;
|
||||
badges?: badge[];
|
||||
}
|
||||
|
||||
interface badge {
|
||||
name: string;
|
||||
color: string;
|
||||
priority: number;
|
||||
}
|
||||
|
||||
const adminBadge: badge = {
|
||||
const adminBadge: UserBadge = {
|
||||
name: "Admin",
|
||||
color: "#CC3333",
|
||||
priority: 99999,
|
||||
};
|
||||
|
||||
const CEOBadge: badge = {
|
||||
const CEOBadge: UserBadge = {
|
||||
name: "CEO",
|
||||
color: "#F97316",
|
||||
priority: 100000,
|
||||
};
|
||||
|
||||
const webDevBadge: badge = {
|
||||
const webDevBadge: UserBadge = {
|
||||
name: "Web Dev",
|
||||
color: "#a855f7",
|
||||
priority: 50000,
|
||||
};
|
||||
|
||||
const botDevBadge: badge = {
|
||||
const botDevBadge: UserBadge = {
|
||||
name: "Bot Dev",
|
||||
color: "#48b2f1",
|
||||
priority: 50001,
|
||||
};
|
||||
|
||||
const fakeData: fakeDataEntry[] = [
|
||||
const fakeData: UserFakeDataEntry[] = [
|
||||
{
|
||||
id: 4,
|
||||
name: "3zachm",
|
||||
|
@ -384,6 +361,7 @@ const fakeData: fakeDataEntry[] = [
|
|||
provider: "7tv",
|
||||
},
|
||||
],
|
||||
badges: [],
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
|
@ -423,6 +401,7 @@ const fakeData: fakeDataEntry[] = [
|
|||
provider: "twitch",
|
||||
},
|
||||
],
|
||||
badges: [],
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
|
@ -462,6 +441,7 @@ const fakeData: fakeDataEntry[] = [
|
|||
provider: "ffz",
|
||||
},
|
||||
],
|
||||
badges: [],
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
|
@ -496,6 +476,7 @@ const fakeData: fakeDataEntry[] = [
|
|||
provider: "twitch",
|
||||
},
|
||||
],
|
||||
badges: [],
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
|
@ -535,6 +516,7 @@ const fakeData: fakeDataEntry[] = [
|
|||
provider: "twitch",
|
||||
},
|
||||
],
|
||||
badges: [],
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
|
@ -574,6 +556,7 @@ const fakeData: fakeDataEntry[] = [
|
|||
provider: "twitch",
|
||||
},
|
||||
],
|
||||
badges: [],
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
|
@ -613,6 +596,7 @@ const fakeData: fakeDataEntry[] = [
|
|||
provider: "twitch",
|
||||
},
|
||||
],
|
||||
badges: [],
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
|
@ -657,6 +641,7 @@ const fakeData: fakeDataEntry[] = [
|
|||
provider: "twitch",
|
||||
},
|
||||
],
|
||||
badges: [],
|
||||
},
|
||||
{
|
||||
id: 13,
|
||||
|
@ -686,6 +671,7 @@ const fakeData: fakeDataEntry[] = [
|
|||
provider: "7tv",
|
||||
},
|
||||
],
|
||||
badges: [],
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
|
@ -720,6 +706,7 @@ const fakeData: fakeDataEntry[] = [
|
|||
provider: "twitch",
|
||||
},
|
||||
],
|
||||
badges: [],
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
|
@ -754,6 +741,7 @@ const fakeData: fakeDataEntry[] = [
|
|||
provider: "twitch",
|
||||
},
|
||||
],
|
||||
badges: [],
|
||||
},
|
||||
{
|
||||
id: 16,
|
||||
|
@ -788,6 +776,7 @@ const fakeData: fakeDataEntry[] = [
|
|||
provider: "twitch",
|
||||
},
|
||||
],
|
||||
badges: [],
|
||||
},
|
||||
{
|
||||
id: 17,
|
||||
|
@ -822,6 +811,7 @@ const fakeData: fakeDataEntry[] = [
|
|||
provider: "twitch",
|
||||
},
|
||||
],
|
||||
badges: [],
|
||||
},
|
||||
{
|
||||
id: 18,
|
||||
|
@ -856,7 +846,6 @@ const fakeData: fakeDataEntry[] = [
|
|||
provider: "twitch",
|
||||
},
|
||||
],
|
||||
badges: [],
|
||||
},
|
||||
];
|
||||
|
||||
export type { fakeDataEntry };
|
||||
|
|
|
@ -2,6 +2,7 @@ import { m, Variants } from "framer-motion";
|
|||
import Link from "next/link";
|
||||
import { ReactElement, useEffect, useState } from "react";
|
||||
import Loading from "../../components/common/Loading";
|
||||
import UserJSONEntry from "../../interfaces/UserJSONEntry";
|
||||
import DashLayout from "../../layouts/DashLayout";
|
||||
|
||||
function Ranking() {
|
||||
|
@ -158,8 +159,7 @@ function Ranking() {
|
|||
>
|
||||
{
|
||||
// generate table rows
|
||||
fakeData.map(
|
||||
(entry: { [key: string]: any }, index: number) => {
|
||||
fakeData.map((entry: UserJSONEntry, index: number) => {
|
||||
// if daily change is negative, make it red
|
||||
let changeClass = " text-lime-500";
|
||||
if (entry.daily_change_percent < 0) {
|
||||
|
@ -191,14 +191,12 @@ function Ranking() {
|
|||
</h1>
|
||||
<h1 className={changeClass}>
|
||||
{(
|
||||
Math.round(entry.daily_change_percent * 1000) /
|
||||
10
|
||||
Math.round(entry.daily_change_percent * 1000) / 10
|
||||
).toFixed(1) + "%"}
|
||||
</h1>
|
||||
</m.div>
|
||||
);
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
</m.div>
|
||||
)
|
||||
|
|
|
@ -5,6 +5,8 @@ import DashLayout from "../../../layouts/DashLayout";
|
|||
import Image from "next/image";
|
||||
import Loading from "../../../components/common/Loading";
|
||||
import { GetServerSideProps } from "next";
|
||||
import UserJSONEntry from "../../../interfaces/UserJSONEntry";
|
||||
import APIError from "../../../interfaces/APIError";
|
||||
|
||||
interface EmoteURLs {
|
||||
"7tv": { [key: string]: string };
|
||||
|
@ -15,7 +17,8 @@ interface EmoteURLs {
|
|||
}
|
||||
|
||||
interface UserPageProps {
|
||||
userData: { [key: string]: any };
|
||||
userData: UserJSONEntry;
|
||||
serverError: APIError | null;
|
||||
}
|
||||
|
||||
function UserPage(props: UserPageProps) {
|
||||
|
@ -28,8 +31,9 @@ function UserPage(props: UserPageProps) {
|
|||
|
||||
useEffect(() => {
|
||||
if (!router.isReady) return;
|
||||
if (props.userData.error) {
|
||||
setErrorCode(props.userData.error.code);
|
||||
// if it is of
|
||||
if (props.serverError) {
|
||||
setErrorCode(props.serverError.error.code);
|
||||
}
|
||||
fetch("/api/emotes")
|
||||
.then((res) => res.json())
|
||||
|
@ -342,18 +346,15 @@ function UserPage(props: UserPageProps) {
|
|||
<h1>Shares</h1>
|
||||
<h1>{props.userData.shares.toLocaleString("en-US")}</h1>
|
||||
<h1>Trades</h1>
|
||||
<h1>{(props.userData.trades ?? 0).toLocaleString("en-US")}</h1>
|
||||
<h1>{(0).toLocaleString("en-US")}</h1>
|
||||
<h1>Peak rank</h1>
|
||||
<h1>{(props.userData.peak_rank ?? 0).toLocaleString("en-US")}</h1>
|
||||
<h1>{(0).toLocaleString("en-US")}</h1>
|
||||
<h1>Joined</h1>
|
||||
<h1>
|
||||
{new Date(props.userData.joined ?? 0).toLocaleDateString(
|
||||
"en-US",
|
||||
{
|
||||
{new Date(0).toLocaleDateString("en-US", {
|
||||
year: "numeric",
|
||||
month: "short",
|
||||
}
|
||||
)}
|
||||
})}
|
||||
</h1>
|
||||
</m.div>
|
||||
{/* User's Favorite Emote */}
|
||||
|
@ -565,25 +566,30 @@ export const getServerSideProps: GetServerSideProps<UserPageProps> = async (
|
|||
`/api/fakeUsers?u=${context.query.username}`,
|
||||
process.env.NEXT_PUBLIC_URL
|
||||
);
|
||||
// TODO: add error handling
|
||||
const res = await fetch(url);
|
||||
let user = await res.json();
|
||||
// return error in user.data if user not found
|
||||
if (user.error) {
|
||||
user = { data: user };
|
||||
return {
|
||||
props: {
|
||||
userData: user,
|
||||
serverError: user,
|
||||
},
|
||||
};
|
||||
}
|
||||
return { props: { userData: user.data } };
|
||||
return { props: { userData: user.data[0], serverError: null } };
|
||||
};
|
||||
|
||||
UserPage.getLayout = function getLayout(page: ReactElement) {
|
||||
const { userData } = page.props;
|
||||
const { userData, serverError } = page.props;
|
||||
const metaTags = {
|
||||
title: !userData.error
|
||||
title: !serverError
|
||||
? `${userData.name ?? "User 404"} - toffee`
|
||||
: "User 404 - toffee",
|
||||
description: !userData.error
|
||||
description: !serverError
|
||||
? `${userData.name}'s portfolio on toffee`
|
||||
: "Couldn't find that user on toffee... :(",
|
||||
imageUrl: !userData.error ? userData.avatar_url : undefined,
|
||||
imageUrl: !serverError ? userData.avatar_url : undefined,
|
||||
misc: {
|
||||
"twitter:card": "summary",
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue