166 lines
5.2 KiB
TypeScript
166 lines
5.2 KiB
TypeScript
import { m, Variants } from "framer-motion";
|
|
import Head from "next/head";
|
|
import { ReactElement, useEffect, useState } from "react";
|
|
import DashLayout from "../../layouts/DashLayout";
|
|
import { fakeDataEntry } from "../api/fakeRanking";
|
|
|
|
function Ranking() {
|
|
const [sortBy, setSortBy] = useState("netWorth");
|
|
const [fakeData, setFakeData] = useState([]);
|
|
|
|
useEffect(() => {
|
|
fetch(`/api/fakeRanking?s=${sortBy}`)
|
|
.then((res) => res.json())
|
|
.then((data) => {
|
|
setFakeData(data.data);
|
|
});
|
|
}, [sortBy]);
|
|
|
|
return (
|
|
<>
|
|
<Head>
|
|
<title>Ranking - InvestBot</title>
|
|
</Head>
|
|
<div className="flex w-full justify-center">
|
|
<m.div
|
|
className="ml-3 flex w-full flex-col items-center justify-start font-spaceMono font-semibold lg:ml-0"
|
|
variants={containerVariants}
|
|
initial="initial"
|
|
animate="animate"
|
|
>
|
|
{/* hidden if smaller than lg */}
|
|
<m.h1
|
|
className="hidden bg-gradient-to-tr from-purple-500 to-purple-100 bg-clip-text py-10 text-center font-plusJakarta text-5xl font-bold text-white text-transparent lg:block lg:text-6xl"
|
|
variants={headerVariants}
|
|
>
|
|
Top Investors
|
|
</m.h1>
|
|
{/* TODO: responsive for extremely skinny displays (i.e. galaxy fold), or really for mobile entirely so info is not lost */}
|
|
<m.div
|
|
className="text-md inline-grid w-full rounded-t-2xl bg-zinc-800 bg-opacity-70 p-3 pt-4 backdrop-blur sm:text-xl"
|
|
variants={rankingCardVariants}
|
|
initial="initial"
|
|
animate="animate"
|
|
>
|
|
<m.div className="inline-grid w-full grid-flow-col grid-cols-[0.75fr_4fr_3fr_2fr] gap-2 border-b-2 border-zinc-400 px-5 pb-3 text-right text-gray-300 md:grid-cols-[0.5fr_4fr_repeat(3,_2fr)_1.5fr]">
|
|
<m.h1 className="text-left md:text-center">#</m.h1>
|
|
<m.h1
|
|
className="overflow-hidden overflow-ellipsis whitespace-nowrap text-left"
|
|
onClick={() => setSortBy("name")}
|
|
>
|
|
Name
|
|
</m.h1>
|
|
<m.h1 onClick={() => setSortBy("netWorth")}>Assets</m.h1>
|
|
<m.h1
|
|
className="hidden md:block"
|
|
onClick={() => setSortBy("points")}
|
|
>
|
|
Points
|
|
</m.h1>
|
|
<m.h1
|
|
className="hidden md:block"
|
|
onClick={() => setSortBy("shares")}
|
|
>
|
|
Shares
|
|
</m.h1>
|
|
<m.h1 onClick={() => setSortBy("dailyChange")}>Daily</m.h1>
|
|
</m.div>
|
|
{
|
|
// TODO: add arrow to show which column is being sorted by and which direction
|
|
fakeData.map((entry: fakeDataEntry, index) => {
|
|
let changeClass = " text-lime-500";
|
|
if (entry.dailyChangePercent < 0) {
|
|
changeClass = " text-red-500";
|
|
}
|
|
return (
|
|
<m.div key={entry.id}>
|
|
<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]">
|
|
<m.h1 className="text-left md:text-center">
|
|
{index + 1}
|
|
</m.h1>
|
|
<m.h1 className="overflow-hidden overflow-ellipsis whitespace-nowrap text-left">
|
|
{entry.name}
|
|
</m.h1>
|
|
<m.h1>{entry.netWorth.toLocaleString("en-US")}</m.h1>
|
|
<m.h1 className="hidden md:block">
|
|
{entry.points.toLocaleString("en-US")}
|
|
</m.h1>
|
|
<m.h1 className="hidden md:block">
|
|
{entry.shares.toLocaleString("en-US")}
|
|
</m.h1>
|
|
<m.h1 className={changeClass}>
|
|
{(
|
|
Math.round(entry.dailyChangePercent * 1000) / 10
|
|
).toFixed(1) + "%"}
|
|
</m.h1>
|
|
</m.div>
|
|
</m.div>
|
|
);
|
|
})
|
|
}
|
|
</m.div>
|
|
</m.div>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|
|
|
|
const containerVariants: Variants = {
|
|
initial: {
|
|
opacity: 1,
|
|
},
|
|
animate: {
|
|
opacity: 1,
|
|
transition: {
|
|
duration: 2,
|
|
delayChildren: 0.5,
|
|
staggerChildren: 0.25,
|
|
type: "spring",
|
|
bounce: 0.5,
|
|
stiffness: 80,
|
|
},
|
|
},
|
|
};
|
|
|
|
const headerVariants: Variants = {
|
|
initial: {
|
|
opacity: 0,
|
|
y: -100,
|
|
},
|
|
animate: {
|
|
opacity: 1,
|
|
y: 0,
|
|
transition: {
|
|
delay: 1.0,
|
|
duration: 1.0,
|
|
type: "spring",
|
|
bounce: 0.5,
|
|
stiffness: 60,
|
|
},
|
|
},
|
|
};
|
|
|
|
const rankingCardVariants: Variants = {
|
|
initial: {
|
|
opacity: 0,
|
|
y: 300,
|
|
},
|
|
animate: {
|
|
opacity: 1,
|
|
y: 0,
|
|
transition: {
|
|
duration: 3,
|
|
delayChildren: 0.5,
|
|
staggerChildren: 0.25,
|
|
type: "spring",
|
|
bounce: 0.5,
|
|
stiffness: 40,
|
|
},
|
|
},
|
|
};
|
|
|
|
Ranking.getLayout = function getLayout(page: ReactElement) {
|
|
return <DashLayout>{page}</DashLayout>;
|
|
};
|
|
|
|
export default Ranking;
|