mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-02-15 04:32:13 +00:00
feat: Add SeedersAndPeers component with skeleton loader
This commit is contained in:
parent
1872ff1d24
commit
58693fdb00
4 changed files with 154 additions and 0 deletions
|
@ -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>
|
||||
);
|
||||
}
|
|
@ -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>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
export type TorrentData = {
|
||||
seeders: number;
|
||||
peers: number;
|
||||
lastTracked?: Date;
|
||||
};
|
|
@ -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,
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue