feat: Add SeedersAndPeers component with skeleton loader

This commit is contained in:
ChristoferMendes 2024-05-10 12:10:08 -03:00
parent 1872ff1d24
commit 58693fdb00
4 changed files with 154 additions and 0 deletions

View file

@ -0,0 +1,20 @@
import Skeleton from "react-loading-skeleton";
export function SeedersAndPeersSkeleton() {
return (
<div
style={{
display: "flex",
}}
>
<Skeleton width={40} height={20} />
<Skeleton
width={40}
height={20}
style={{
marginLeft: "12px",
}}
/>
</div>
);
}

View file

@ -0,0 +1,54 @@
import { GameRepack } from "@types";
import { Sprout, Users } from "lucide-react";
import { useMagnetData } from "./useMagnetData";
import { Tooltip } from "@renderer/components/tooltip/tooltip";
import { SeedersAndPeersSkeleton } from "./seeders-and-peers-skeleton";
import { vars } from "@renderer/theme.css";
interface SeedersAndPeersProps {
repack: GameRepack;
}
export function SeedersAndPeers({ repack }: Readonly<SeedersAndPeersProps>) {
const { magnetData, isLoading, error } = useMagnetData(repack.magnet);
if (isLoading) {
return <SeedersAndPeersSkeleton />;
}
if (error) {
return null;
}
return (
<div
style={{
display: "flex",
justifyContent: "space-around",
}}
>
<Tooltip tooltipText="Seeders">
<Sprout size={16} stroke={vars.color.bodyText} />
<span
style={{
marginLeft: "7px",
marginRight: "8px",
}}
>
{magnetData?.seeders}
</span>
</Tooltip>
<Tooltip tooltipText="Peers">
<Users size={16} stroke={vars.color.bodyText} />
<span
style={{
marginLeft: "7px",
}}
>
{magnetData?.peers}
</span>
</Tooltip>
</div>
);
}

View file

@ -0,0 +1,5 @@
export type TorrentData = {
seeders: number;
peers: number;
lastTracked?: Date;
};

View file

@ -0,0 +1,75 @@
import { useCallback, useEffect, useState } from "react";
import { TorrentData } from "./types";
const cache: Record<string, TorrentData> = {};
export function useMagnetData(magnet: string) {
const [magnetData, setMagnetData] = useState<TorrentData | null>(cache[magnet] || null);
const [isLoading, setIsLoading] = useState(() => {
if (cache[magnet]) {
return false;
}
return true;
});
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
if (!magnet) {
return;
}
if (cache[magnet]) {
setMagnetData(cache[magnet]);
setIsLoading(false);
return;
}
window.electron.getMagnetData(magnet).then(
(result) => {
if (result) {
setMagnetData(result);
setIsLoading(false);
cache[magnet] = result;
cache[magnet].lastTracked = new Date();
}
},
(error) => {
setError(error);
setIsLoading(false);
}
);
}, []);
const invalidateCache = useCallback(() => {
const TWO_MINUTES = 2 * 60 * 1000;
const cacheExpiresIn = TWO_MINUTES;
Object.keys(cache).forEach((key) => {
const lastTracked = cache[key].lastTracked;
if (!lastTracked) {
return;
}
if (Date.now() - lastTracked.getTime() > cacheExpiresIn) {
delete cache[key];
}
});
}, []);
useEffect(() => {
invalidateCache();
return () => {
invalidateCache();
}
}, []);
return {
magnetData,
isLoading,
error,
};
}