mhsf-dev/src/components/FavoritesView.tsx

163 lines
5.8 KiB
TypeScript
Raw Normal View History

2024-10-05 09:07:26 -05:00
/*
* MHSF, Minehut Server List
* All external content is rather licensed under the ECA Agreement
* located here: https://list.mlnehut.com/docs/legal/external-content-agreement
*
* All code under MHSF is licensed under the MIT License
* by open source contributors
*
* Copyright (c) 2024 dvelo
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
2024-07-23 18:49:21 -05:00
"use client";
import { useState } from "react";
2024-07-23 18:49:21 -05:00
import { Spinner } from "./ui/spinner";
import { Card, CardHeader, CardTitle } from "./ui/card";
2024-10-04 21:06:02 -05:00
import type { ServerResponse } from "@/lib/types/mh-server";
2024-07-23 18:49:21 -05:00
import { useEffectOnce } from "@/lib/useEffectOnce";
import { Button } from "./ui/button";
2024-08-03 09:51:45 -05:00
import { Copy, Layers, XIcon } from "lucide-react";
2024-07-23 18:49:21 -05:00
import toast from "react-hot-toast";
import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip";
2024-08-03 09:51:45 -05:00
import { getAccountFavorites } from "@/lib/api";
import { useRouter } from "@/lib/useRouter";
2024-08-18 01:15:27 -05:00
import { Skeleton } from "./ui/skeleton";
import FadeIn from "react-fade-in/lib/FadeIn";
2024-07-23 18:49:21 -05:00
export default function FavoritesView() {
const [apiFavorites, setApiFavorites] = useState<any>([]);
const [loading, setLoading] = useState(true);
const router = useRouter();
2024-07-23 18:49:21 -05:00
useEffectOnce(() => {
2024-08-03 09:51:45 -05:00
getAccountFavorites().then((d) => {
let num = 0;
d.forEach((a: any, i: number) => {
fetch("https://api.minehut.com/server/" + a + "?byName=true").then(
(b) =>
b.json().then((c) => {
num++;
2024-10-04 21:06:02 -05:00
const apiClone = apiFavorites;
2024-08-03 09:51:45 -05:00
apiClone.push(c.server);
setApiFavorites(apiClone);
2024-10-04 21:06:02 -05:00
if (num === d.length) {
2024-08-03 09:51:45 -05:00
setLoading(false);
}
})
);
2024-07-23 18:49:21 -05:00
});
2024-10-04 21:06:02 -05:00
if (d.length === 0) setLoading(false);
2024-07-23 18:49:21 -05:00
});
});
if (loading) {
return (
<>
2024-08-18 01:15:27 -05:00
<div className="grid grid-cols-4 gap-4">
<Skeleton className="h-[147px] rounded-xl" />
<Skeleton className="h-[147px] rounded-xl" />
<Skeleton className="h-[147px] rounded-xl" />
<Skeleton className="h-[147px] rounded-xl" />
<Skeleton className="h-[147px] rounded-xl" />
<Skeleton className="h-[147px] rounded-xl" />
<Skeleton className="h-[147px] rounded-xl" />
<Skeleton className="h-[147px] rounded-xl" />
<Skeleton className="h-[147px] rounded-xl" />
<Skeleton className="h-[147px] rounded-xl" />
<Skeleton className="h-[147px] rounded-xl" />
<Skeleton className="h-[147px] rounded-xl" />
</div>
2024-07-23 18:49:21 -05:00
</>
);
}
return (
<>
2024-10-04 21:06:02 -05:00
{apiFavorites.length === 0 && (
2024-07-26 00:46:53 -05:00
<div className="flex items-center justify-center">
<XIcon />
Your favorites are empty. Maybe favorite a server!
</div>
)}
2024-08-18 01:15:27 -05:00
<FadeIn>
<div className="grid sm:grid-cols-4 gap-4">
{apiFavorites.map((server: ServerResponse) => (
<Card key={server.name}>
<CardHeader>
<CardTitle>{server.name}</CardTitle>
<div>
<Button
size="icon"
variant="secondary"
className="min-w-[128px] max-w-[328px] mb-2 h-[32px] max-md:hidden"
onClick={() => {
navigator.clipboard.writeText(
server.name + ".mshf.minehut.gg"
);
toast.success("Copied IP to clipboard");
}}
>
<Copy size={18} />
<code className="ml-2">{server.name}</code>
</Button>
<Tooltip>
<TooltipTrigger>
<Button
size="icon"
variant="secondary"
className="w-[32px] h-[32px] mb-2 ml-2 max-md:hidden"
onClick={() => {
router.push("/server/" + server.name);
}}
>
<Layers size={18} />
</Button>
</TooltipTrigger>
<TooltipContent>
Open up the server page to see more information about the
server
</TooltipContent>
</Tooltip>
</div>
<code className="text-[14px]">
{convert(server.joins)} total joins {" "}
{server.online ? "Online" : "Offline"}
</code>
</CardHeader>
</Card>
))}
</div>
</FadeIn>
2024-07-23 18:49:21 -05:00
</>
);
}
function convert(value: number) {
2024-07-26 15:40:13 -05:00
var result: string = value.toString();
2024-07-23 18:49:21 -05:00
if (value >= 1000000) {
result = Math.floor(value / 1000000) + "m";
} else if (value >= 1000) {
result = Math.floor(value / 1000) + "k";
}
return result;
}