add loading animation to the player and server page when clicking search
All checks were successful
Deploy App / docker (ubuntu-latest) (push) Successful in 1m29s

This commit is contained in:
Lee 2024-04-18 07:28:59 +01:00
parent 428a95c54d
commit 49de624a88
8 changed files with 78 additions and 11 deletions

@ -32,6 +32,7 @@
"react-countup": "^6.5.3", "react-countup": "^6.5.3",
"react-dom": "^18", "react-dom": "^18",
"react-hook-form": "^7.51.3", "react-hook-form": "^7.51.3",
"react-spinners": "^0.13.8",
"react-syntax-highlighter": "^15.5.0", "react-syntax-highlighter": "^15.5.0",
"react-use-websocket": "3.0.0", "react-use-websocket": "3.0.0",
"tailwind-merge": "^2.2.2", "tailwind-merge": "^2.2.2",

13
pnpm-lock.yaml generated

@ -74,6 +74,9 @@ dependencies:
react-hook-form: react-hook-form:
specifier: ^7.51.3 specifier: ^7.51.3
version: 7.51.3(react@18.2.0) version: 7.51.3(react@18.2.0)
react-spinners:
specifier: ^0.13.8
version: 0.13.8(react-dom@18.2.0)(react@18.2.0)
react-syntax-highlighter: react-syntax-highlighter:
specifier: ^15.5.0 specifier: ^15.5.0
version: 15.5.0(react@18.2.0) version: 15.5.0(react@18.2.0)
@ -4976,6 +4979,16 @@ packages:
use-sidecar: 1.1.2(@types/react@18.2.78)(react@18.2.0) use-sidecar: 1.1.2(@types/react@18.2.78)(react@18.2.0)
dev: false dev: false
/react-spinners@0.13.8(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-3e+k56lUkPj0vb5NDXPVFAOkPC//XyhKPJjvcGjyMNPWsBKpplfeyialP74G7H7+It7KzhtET+MvGqbKgAqpZA==}
peerDependencies:
react: ^16.0.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0
dependencies:
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/react-style-singleton@2.2.1(@types/react@18.2.78)(react@18.2.0): /react-style-singleton@2.2.1(@types/react@18.2.78)(react@18.2.0):
resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==}
engines: {node: '>=10'} engines: {node: '>=10'}

@ -69,7 +69,7 @@ export default async function Page({ params: { id } }: Params): Promise<ReactEle
<h1 className="text-xl">Lookup a Player</h1> <h1 className="text-xl">Lookup a Player</h1>
<p>You can enter a players uuid or username to get information about the player.</p> <p>You can enter a players uuid or username to get information about the player.</p>
<LookupPlayer /> <LookupPlayer currentPlayer={id[0]} />
</div> </div>
{error && <ErrorCard message={error} />} {error && <ErrorCard message={error} />}

@ -124,7 +124,7 @@ export default async function Page({ params: { platform, hostname } }: Params):
<h1 className="text-xl">Lookup a {invalidPlatform ? "" : capitalizeFirstLetter(platform)} Server</h1> <h1 className="text-xl">Lookup a {invalidPlatform ? "" : capitalizeFirstLetter(platform)} Server</h1>
<p>You can enter a server hostname to get information about the server.</p> <p>You can enter a server hostname to get information about the server.</p>
<LookupServer currentPlatform={platform.toLocaleLowerCase()} /> <LookupServer currentPlatform={platform.toLowerCase()} currentServer={hostname[0]} />
</div> </div>
{error && <ErrorCard message={error} />} {error && <ErrorCard message={error} />}

@ -3,14 +3,24 @@
import { useToast } from "@/common/use-toast"; import { useToast } from "@/common/use-toast";
import { getPlayer } from "mcutils-library"; import { getPlayer } from "mcutils-library";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { ReactElement } from "react"; import { ReactElement, useState } from "react";
import ScaleLoader from "react-spinners/ScaleLoader";
import { Button } from "../ui/button"; import { Button } from "../ui/button";
import { Input } from "../ui/input"; import { Input } from "../ui/input";
import { Label } from "../ui/label"; import { Label } from "../ui/label";
export function LookupPlayer(): ReactElement { type PlayerLookupProps = {
/**
* The last displayed player.
*/
currentPlayer: string;
};
export function LookupPlayer({ currentPlayer }: PlayerLookupProps): ReactElement {
console.log(currentPlayer);
const router = useRouter(); const router = useRouter();
const { toast } = useToast(); const { toast } = useToast();
const [loading, setLoading] = useState<boolean>(false);
/** /**
* Lookup a server based on the platform * Lookup a server based on the platform
@ -23,8 +33,15 @@ export function LookupPlayer(): ReactElement {
return; return;
} }
// Ignore the same player
if (query.toLowerCase() == currentPlayer.toLowerCase()) {
return;
}
try { try {
setLoading(true);
const player = await getPlayer(query); const player = await getPlayer(query);
router.push(`/player/${player.username}`); router.push(`/player/${player.username}`);
} catch (err) { } catch (err) {
toast({ toast({
@ -51,7 +68,10 @@ export function LookupPlayer(): ReactElement {
</div> </div>
</div> </div>
<Button type="submit">Search</Button> <Button type="submit" className="flex gap-2">
{loading && <ScaleLoader width={1} height={20} radius={2} />}
Search
</Button>
</form> </form>
); );
} }

@ -4,7 +4,8 @@ import { capitalizeFirstLetter } from "@/common/string-utils";
import { useToast } from "@/common/use-toast"; import { useToast } from "@/common/use-toast";
import { ServerPlatform, getServer } from "mcutils-library"; import { ServerPlatform, getServer } from "mcutils-library";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { ReactElement } from "react"; import { ReactElement, useState } from "react";
import ScaleLoader from "react-spinners/ScaleLoader";
import { Button } from "../ui/button"; import { Button } from "../ui/button";
import { Input } from "../ui/input"; import { Input } from "../ui/input";
import { Label } from "../ui/label"; import { Label } from "../ui/label";
@ -12,14 +13,21 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from ".
type LookupServerProps = { type LookupServerProps = {
/** /**
* The current platform. * The last displayed platform.
*/ */
currentPlatform: string; currentPlatform: string | undefined;
/**
* The last displayed server.
*/
currentServer: string | undefined;
}; };
export function LookupServer({ currentPlatform }: LookupServerProps): ReactElement { export function LookupServer({ currentPlatform, currentServer }: LookupServerProps): ReactElement {
console.log(currentPlatform, currentServer);
const router = useRouter(); const router = useRouter();
const { toast } = useToast(); const { toast } = useToast();
const [loading, setLoading] = useState<boolean>(false);
/** /**
* Lookup a server based on the platform * Lookup a server based on the platform
@ -33,7 +41,15 @@ export function LookupServer({ currentPlatform }: LookupServerProps): ReactEleme
} }
try { try {
setLoading(true);
const server = await getServer(platform, query); const server = await getServer(platform, query);
// Ignore the same server
if (currentServer !== undefined && server.hostname == currentServer.toLowerCase()) {
setLoading(false);
return;
}
router.push(`/server/${platform}/${server.hostname}`); router.push(`/server/${platform}/${server.hostname}`);
} catch (err) { } catch (err) {
toast({ toast({
@ -78,7 +94,10 @@ export function LookupServer({ currentPlatform }: LookupServerProps): ReactEleme
</div> </div>
</div> </div>
<Button type="submit">Search</Button> <Button type="submit" className="flex gap-2">
{loading && <ScaleLoader width={1} height={20} radius={2} />}
Search
</Button>
</form> </form>
); );
} }

@ -1,3 +1,6 @@
/**
* Re-useable colors.
*/
export const Colors = { export const Colors = {
green: "#0FFF50", green: "#0FFF50",
red: "#8B0000", red: "#8B0000",

@ -1,9 +1,20 @@
import { Metadata } from "next"; import { Metadata } from "next";
type Embed = { type Embed = {
/**
* The title of the embed.
*/
title: string; title: string;
/**
* The description of the embed.
*/
description: string; description: string;
image?: string | null;
/**
* The image to show as the thumbmail.
*/
image?: string;
}; };
/** /**