Skip to content

Commit

Permalink
add spinners when loading
Browse files Browse the repository at this point in the history
  • Loading branch information
minhd-vu committed Feb 28, 2024
1 parent e47188c commit 3942f6f
Show file tree
Hide file tree
Showing 14 changed files with 168 additions and 279 deletions.
117 changes: 117 additions & 0 deletions components/Button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { ReactNode, useContext, useState } from "react";
import { useSWRConfig } from "swr";
import { ErrorContext } from "./App";

export function Button({
route,
children,
className,
body,
spinnerSize = "sm",
}: {
route: string;
children: ReactNode;
className?: string;
body?: string;
spinnerSize?: string;
}) {
"use client";

const [isLoading, setLoading] = useState(false);
const { mutate } = useSWRConfig();
const { setError } = useContext(ErrorContext);

async function onClick() {
setLoading(true);

const res = await fetch(route, {
method: "POST",
headers: { "Content-Type": "application/json" },
body,
});

if (!res.ok) {
setError(await res.json());
setLoading(false);
return;
}

mutate("/api/user");
}

return (
<button className={`btn ${className}`} onClick={() => onClick()}>
<span className={isLoading ? "invisible" : "visible"}>{children}</span>
{isLoading && (
<span
className={`loading loading-spinner loading-${spinnerSize} absolute`}
/>
)}
</button>
);
}

export function ConfirmKill() {
return (
<Button className="btn-success" route="/api/kill/confirm">
Confirm Kill
</Button>
);
}

export function CreateParty() {
return (
<Button className="btn-primary" route="/api/party">
Create Party
</Button>
);
}

export function DenyKill() {
return (
<Button className="btn-error" route="/api/kill/deny">
Deny Kill
</Button>
);
}

export function KillTarget({ pending }: { pending: boolean }) {
if (pending) {
return (
<button className="btn btn-accent">
Pending
<span className="loading loading-dots loading-sm" />
</button>
);
}

return (
<Button route="/api/kill" className="btn-accent">
Kill Target
</Button>
);
}

export function LeaveParty() {
return (
<Button route="/api/party/leave" className="btn-error">
Leave Party
</Button>
);
}

export function StartGame() {
return (
<Button route="/api/party/start" className="btn-success">
Start Game
</Button>
);
}

export function StopGame() {
return (
<Button route="/api/party/stop" className="btn-warning">
Stop Game
</Button>
);
}
29 changes: 0 additions & 29 deletions components/ConfirmKill.tsx

This file was deleted.

25 changes: 0 additions & 25 deletions components/CreateParty.tsx

This file was deleted.

29 changes: 0 additions & 29 deletions components/DenyKill.tsx

This file was deleted.

14 changes: 13 additions & 1 deletion components/JoinParty.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import { Controller, SubmitHandler, useForm } from "react-hook-form";
import { useSWRConfig } from "swr";
import { PartyJoinBody } from "@/lib/party";
import { toSentence } from "./Alert";
import { useState } from "react";

export default function JoinParty() {
const [isLoading, setLoading] = useState(false);
const { mutate } = useSWRConfig();
const {
handleSubmit,
Expand All @@ -15,6 +17,8 @@ export default function JoinParty() {
} = useForm<PartyJoinBody>();

const onSubmit: SubmitHandler<PartyJoinBody> = async ({ code }) => {
setLoading(true);

const res = await fetch("/api/party/join", {
method: "POST",
headers: {
Expand All @@ -25,6 +29,7 @@ export default function JoinParty() {

if (!res.ok) {
setError("code", { message: await res.json() });
setLoading(false);
return;
}

Expand Down Expand Up @@ -73,7 +78,14 @@ export default function JoinParty() {
</label>
)}
/>
<button className="btn btn-primary">Join Party</button>
<button className="btn btn-primary">
<span className={isLoading ? "invisible" : "visible"}>
Join Party
</span>
{isLoading && (
<span className="loading loading-spinner loading-sm absolute" />
)}
</button>
</div>
<p className="text-sm text-error mt-1">
{toSentence(errors.code?.message)}
Expand Down
34 changes: 7 additions & 27 deletions components/KickPlayer.tsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,14 @@
"use client";

import { useContext } from "react";
import { useSWRConfig } from "swr";
import { ErrorContext } from "./App";
import { Button } from "./Button";

export default function KickPlayer({ playerId }: { playerId: string }) {
const { setError } = useContext(ErrorContext);
const { mutate } = useSWRConfig();

async function onClick() {
const res = await fetch("/api/party/kick", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ playerId }),
});

if (!res.ok) {
setError(await res.json());
return;
}

mutate("/api/user");
}

return (
<button
className="btn btn-square btn-xs btn-error"
onClick={() => onClick()}
<Button
route="/api/party/kick"
className="btn-square btn-xs btn-error"
spinnerSize="xs"
body={JSON.stringify({ playerId })}
>
<svg
xmlns="http://www.w3.org/2000/svg"
Expand All @@ -44,6 +24,6 @@ export default function KickPlayer({ playerId }: { playerId: string }) {
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</Button>
);
}
38 changes: 0 additions & 38 deletions components/KillTarget.tsx

This file was deleted.

30 changes: 0 additions & 30 deletions components/LeaveParty.tsx

This file was deleted.

Loading

0 comments on commit 3942f6f

Please sign in to comment.