sort visualization and reverse order init

This commit is contained in:
3zachm 2022-12-24 17:41:25 -08:00
parent e8d337bfeb
commit 3c9556369a
2 changed files with 205 additions and 110 deletions

View file

@ -9,6 +9,7 @@ export default async function handler(
res: NextApiResponse<Data> res: NextApiResponse<Data>
) { ) {
const sortBy = req.query.s ? (req.query.s as string) : undefined; const sortBy = req.query.s ? (req.query.s as string) : undefined;
const sortAsc = req.query.a ? (req.query.a as string) : undefined;
let data = fakeData; let data = fakeData;
if (sortBy) { if (sortBy) {
@ -25,6 +26,10 @@ export default async function handler(
} else if (sortBy === "name") { } else if (sortBy === "name") {
data = data.sort((a, b) => a.name.localeCompare(b.name)); data = data.sort((a, b) => a.name.localeCompare(b.name));
} }
if (sortAsc === "true") {
// slow but only needed for temporary fake data anyway
data = data.reverse();
}
} }
res.status(200).json({ data }); res.status(200).json({ data });
@ -48,7 +53,7 @@ const fakeData: fakeDataEntry[] = [
points: 70, /// uninvested points points: 70, /// uninvested points
shares: 20, shares: 20,
dailyChange: -500, dailyChange: -500,
dailyChangePercent: -0.523, dailyChangePercent: -0.0498504486540378863409770687936,
}, },
{ {
id: 1, id: 1,
@ -57,7 +62,7 @@ const fakeData: fakeDataEntry[] = [
points: 10020, points: 10020,
shares: 200, shares: 200,
dailyChange: 5420, dailyChange: 5420,
dailyChangePercent: 0.14, dailyChangePercent: 0.0379259673920649359736897347981,
}, },
{ {
id: 2, id: 2,
@ -70,138 +75,138 @@ const fakeData: fakeDataEntry[] = [
}, },
{ {
id: 3, id: 3,
name: "SecondSock", name: "SecondSockSan",
netWorth: 153495, netWorth: 153495,
points: 15020, points: 15020,
shares: 20, shares: 20,
dailyChange: 5432, dailyChange: -10432,
dailyChangePercent: 0.104, dailyChangePercent: -0.06796312583471774324896576435715,
}, },
{ {
id: 0, id: 0,
name: "Ente", name: "e__n__t__e",
netWorth: 429481824, netWorth: 429481824,
points: 1002022, points: 1002022,
shares: 94214, shares: 94214,
dailyChange: 3294444224, dailyChange: 329444422,
dailyChangePercent: 0.94, dailyChangePercent: 4.2932124926634939999741296760186,
}, },
{ {
id: 5, id: 5,
name: "ObnoxiouslyLongNameWICKED", name: "luckytohavefoundyou14252",
netWorth: 0, netWorth: 8024,
points: 100, points: 423,
shares: 0, shares: 4,
dailyChange: 0, dailyChange: 9,
dailyChangePercent: 0, dailyChangePercent: 0.00112163509471585244267198404786,
}, },
{ {
id: 6, id: 6,
name: "User", name: "ZeroxZerich",
netWorth: 0, netWorth: 842190,
points: 100, points: 88542,
shares: 0, shares: 532,
dailyChange: 0, dailyChange: -10219,
dailyChangePercent: 0, dailyChangePercent: -0.01213384153219582279533121979601,
}, },
{ {
id: 7, id: 7,
name: "User", name: "joeeyo",
netWorth: 0, netWorth: 10000000,
points: 100, points: 9999979,
shares: 0, shares: 1,
dailyChange: 0, dailyChange: 1,
dailyChangePercent: 0, dailyChangePercent: 0.0000001,
}, },
{ {
id: 8, id: 8,
name: "User", name: "dd_maru",
netWorth: 0, netWorth: 10328421,
points: 100, points: 328421,
shares: 0, shares: 252,
dailyChange: 0, dailyChange: 85192,
dailyChangePercent: 0, dailyChangePercent: 0.00824830823607984221402284047097,
}, },
{ {
id: 9, id: 9,
name: "User", name: "Goldeneye128",
netWorth: 0, netWorth: 58292,
points: 100, points: 6521,
shares: 0, shares: 63,
dailyChange: 0, dailyChange: -1942,
dailyChangePercent: 0, dailyChangePercent: -0.03331503465312564331297605160228,
}, },
{ {
id: 10, id: 10,
name: "User", name: "lilpastatv",
netWorth: 0, netWorth: 7328919,
points: 100, points: 40,
shares: 0, shares: 93,
dailyChange: 0, dailyChange: 921821,
dailyChangePercent: 0, dailyChangePercent: 0.12577857662228222197571019682439,
}, },
{ {
id: 11, id: 11,
name: "User", name: "domiswitch",
netWorth: 0, netWorth: 43290,
points: 100, points: 5002,
shares: 0, shares: 15,
dailyChange: 0, dailyChange: 2429,
dailyChangePercent: 0, dailyChangePercent: 0.05610995610995610995610995610996,
}, },
{ {
id: 12, id: 12,
name: "User", name: "minosura",
netWorth: 0, netWorth: 904328,
points: 100, points: 32901,
shares: 0, shares: 83,
dailyChange: 0, dailyChange: 94821,
dailyChangePercent: 0, dailyChangePercent: 0.10485244291894091524314186887943,
}, },
{ {
id: 13, id: 13,
name: "User", name: "scienceteam_member",
netWorth: 0, netWorth: 34894,
points: 100, points: 958,
shares: 0, shares: 5,
dailyChange: 0, dailyChange: -7964,
dailyChangePercent: 0, dailyChangePercent: -0.22823408035765461110792686421734,
}, },
{ {
id: 14, id: 14,
name: "User", name: "witchdev",
netWorth: 0, netWorth: 94382912,
points: 100, points: 8532,
shares: 0, shares: 329,
dailyChange: 0, dailyChange: -421,
dailyChangePercent: 0, dailyChangePercent: -0.0000044605531984433792422085896,
}, },
{ {
id: 15, id: 15,
name: "User", name: "justone123879",
netWorth: 0, netWorth: 8889123,
points: 100, points: 86333,
shares: 0, shares: 153,
dailyChange: 0, dailyChange: 53289,
dailyChangePercent: 0, dailyChangePercent: 0.00599485461051669551653183334284,
}, },
{ {
id: 16, id: 16,
name: "User", name: "marcelr_",
netWorth: 0, netWorth: 400329,
points: 100, points: 39291,
shares: 0, shares: 52,
dailyChange: 0, dailyChange: 1329,
dailyChangePercent: 0, dailyChangePercent: 0.00331976948959480827019776234047,
}, },
{ {
id: 17, id: 17,
name: "User", name: "fossabot",
netWorth: 0, netWorth: 20005,
points: 100, points: 0,
shares: 0, shares: 1,
dailyChange: 0, dailyChange: -31042,
dailyChangePercent: 0, dailyChangePercent: -1.5517120719820044988752811797051,
}, },
]; ];

View file

@ -6,15 +6,75 @@ import { fakeDataEntry } from "../api/fakeRanking";
function Ranking() { function Ranking() {
const [sortBy, setSortBy] = useState("netWorth"); const [sortBy, setSortBy] = useState("netWorth");
const [sortAsc, setSortAsc] = useState(false);
const [fakeData, setFakeData] = useState([]); const [fakeData, setFakeData] = useState([]);
useEffect(() => { useEffect(() => {
fetch(`/api/fakeRanking?s=${sortBy}`) // fetch data from api on change to sort method
fetch(`/api/fakeRanking?s=${sortBy}&a=${sortAsc}`)
.then((res) => res.json()) .then((res) => res.json())
.then((data) => { .then((data) => {
setFakeData(data.data); setFakeData(data.data);
}); });
}, [sortBy]); }, [sortBy, sortAsc]);
const SortSVG = (props: { sortType: string; children?: ReactElement }) => {
// if not current sort, return a line, otherwise return an arrow corresponding to sortAsc
if (sortBy != props.sortType) {
return (
<m.svg
className="ml-2"
origin="center"
width="15"
height="15"
viewBox="0 0 6 6"
x={0}
y={0}
>
<m.line
x1="1"
y1="3"
x2="5"
y2="3"
stroke="white"
stroke-linecap="round"
/>
</m.svg>
);
}
return (
<m.svg
className="ml-2"
origin="center"
width="15"
height="15"
viewBox="0 0 330 330"
x={0}
y={0}
// if asc, rotate 180
animate={{ rotate: sortAsc ? 180 : 0 }}
>
<m.path
d="M325.607,79.393c-5.857-5.857-15.355-5.858-21.213,0.001l-139.39,139.393L25.607,79.393 c-5.857-5.857-15.355-5.858-21.213,0.001c-5.858,5.858-5.858,15.355,0,21.213l150.004,150c2.813,2.813,6.628,4.393,10.606,4.393 s7.794-1.581,10.606-4.394l149.996-150C331.465,94.749,331.465,85.251,325.607,79.393z"
fill="white"
stroke="white"
strokeWidth="15"
strokeLinecap="round"
/>
</m.svg>
);
};
const setSortMethod = (sortType: string) => {
// if same sort, toggle asc
// a change in sort means asc should be false for intuitive behavior
if (sortBy == sortType) {
setSortAsc(!sortAsc);
} else {
setSortAsc(false);
setSortBy(sortType);
}
};
return ( return (
<> <>
@ -37,37 +97,64 @@ function Ranking() {
</m.h1> </m.h1>
{/* TODO: responsive for extremely skinny displays (i.e. galaxy fold), or really for mobile entirely so info is not lost */} {/* TODO: responsive for extremely skinny displays (i.e. galaxy fold), or really for mobile entirely so info is not lost */}
<m.div <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" className="text-md inline-grid w-full rounded-t-2xl bg-zinc-800 bg-opacity-70 p-3 pt-4 sm:text-xl"
variants={rankingCardVariants} variants={rankingCardVariants}
initial="initial" initial="initial"
animate="animate" 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]"> {/* Column names and arrows */}
<m.h1 className="text-left md:text-center">#</m.h1> <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 <h1 className="text-left md:text-center">#</h1>
className="overflow-hidden overflow-ellipsis whitespace-nowrap text-left" <div
onClick={() => setSortBy("name")} className="pointer-events-auto flex cursor-pointer flex-row items-center justify-start"
onClick={() => setSortMethod("name")}
> >
<h1 className="overflow-hidden overflow-ellipsis whitespace-nowrap text-left">
Name Name
</m.h1> </h1>
<m.h1 onClick={() => setSortBy("netWorth")}>Assets</m.h1> <SortSVG sortType="name" />
<m.h1 </div>
className="hidden md:block" <div
onClick={() => setSortBy("points")} className="pointer-events-auto flex cursor-pointer flex-row items-center justify-end"
onClick={() => setSortMethod("netWorth")}
> >
<h1 className="overflow-hidden overflow-ellipsis whitespace-nowrap text-left">
Assets
</h1>
<SortSVG sortType="netWorth" />
</div>
<div
className="pointer-events-auto hidden cursor-pointer flex-row items-center justify-end md:flex"
onClick={() => setSortMethod("points")}
>
<h1 className="overflow-hidden overflow-ellipsis whitespace-nowrap text-left">
Points Points
</m.h1> </h1>
<m.h1 <SortSVG sortType="points" />
className="hidden md:block" </div>
onClick={() => setSortBy("shares")} <div
className="pointer-events-auto hidden cursor-pointer flex-row items-center justify-end md:flex"
onClick={() => setSortMethod("shares")}
> >
<h1 className="overflow-hidden overflow-ellipsis whitespace-nowrap text-left">
Shares Shares
</m.h1> </h1>
<m.h1 onClick={() => setSortBy("dailyChange")}>Daily</m.h1> <SortSVG sortType="shares" />
</m.div> </div>
<div
className="pointer-events-auto flex cursor-pointer flex-row items-center justify-end"
onClick={() => setSortMethod("dailyChange")}
>
<h1 className="overflow-hidden overflow-ellipsis whitespace-nowrap text-left">
Daily
</h1>
<SortSVG sortType="dailyChange" />
</div>
</div>
{ {
// TODO: add arrow to show which column is being sorted by and which direction // generate table rows
fakeData.map((entry: fakeDataEntry, index) => { fakeData.map((entry: fakeDataEntry, index) => {
// if daily change is negative, make it red
let changeClass = " text-lime-500"; let changeClass = " text-lime-500";
if (entry.dailyChangePercent < 0) { if (entry.dailyChangePercent < 0) {
changeClass = " text-red-500"; changeClass = " text-red-500";
@ -105,6 +192,7 @@ function Ranking() {
); );
} }
// entire container page animation
const containerVariants: Variants = { const containerVariants: Variants = {
initial: { initial: {
opacity: 1, opacity: 1,
@ -122,6 +210,7 @@ const containerVariants: Variants = {
}, },
}; };
// header animation if needed
const headerVariants: Variants = { const headerVariants: Variants = {
initial: { initial: {
opacity: 0, opacity: 0,
@ -140,6 +229,7 @@ const headerVariants: Variants = {
}, },
}; };
// table container animation
const rankingCardVariants: Variants = { const rankingCardVariants: Variants = {
initial: { initial: {
opacity: 0, opacity: 0,