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