diff --git a/src/components/delete-mii.tsx b/src/components/delete-mii.tsx index b673802..1747a95 100644 --- a/src/components/delete-mii.tsx +++ b/src/components/delete-mii.tsx @@ -7,6 +7,7 @@ import { createPortal } from "react-dom"; import { Icon } from "@iconify/react"; import LikeButton from "./like-button"; +import SubmitButton from "./submit-button"; interface Props { miiId: number; @@ -20,7 +21,7 @@ export default function DeleteMiiButton({ miiId, miiName, likes }: Props) { const [error, setError] = useState(undefined); - const submit = async () => { + const handleSubmit = async () => { const response = await fetch(`/api/mii/${miiId}/delete`, { method: "DELETE" }); if (!response.ok) { const { error } = await response.json(); @@ -92,9 +93,7 @@ export default function DeleteMiiButton({ miiId, miiName, likes }: Props) { - + , diff --git a/src/components/profile-settings/delete-account.tsx b/src/components/profile-settings/delete-account.tsx index b2bf7f1..c916087 100644 --- a/src/components/profile-settings/delete-account.tsx +++ b/src/components/profile-settings/delete-account.tsx @@ -4,6 +4,7 @@ import { useEffect, useState } from "react"; import { createPortal } from "react-dom"; import { Icon } from "@iconify/react"; import { redirect } from "next/navigation"; +import SubmitButton from "../submit-button"; export default function DeleteAccount() { const [isOpen, setIsOpen] = useState(false); @@ -11,7 +12,7 @@ export default function DeleteAccount() { const [error, setError] = useState(undefined); - const submit = async () => { + const handleSubmit = async () => { const response = await fetch("/api/auth/delete", { method: "DELETE" }); if (!response.ok) { const { error } = await response.json(); @@ -78,9 +79,7 @@ export default function DeleteAccount() { - + , diff --git a/src/components/profile-settings/submit-dialog-button.tsx b/src/components/profile-settings/submit-dialog-button.tsx index ba3ee10..fe6e227 100644 --- a/src/components/profile-settings/submit-dialog-button.tsx +++ b/src/components/profile-settings/submit-dialog-button.tsx @@ -3,6 +3,7 @@ import { useEffect, useState } from "react"; import { createPortal } from "react-dom"; import { Icon } from "@iconify/react"; +import SubmitButton from "../submit-button"; interface Props { title: string; @@ -71,9 +72,7 @@ export default function SubmitDialogButton({ title, description, onSubmit, error - + , diff --git a/src/components/submit-button.tsx b/src/components/submit-button.tsx new file mode 100644 index 0000000..d4cc883 --- /dev/null +++ b/src/components/submit-button.tsx @@ -0,0 +1,32 @@ +"use client"; + +import { useState } from "react"; +import { Icon } from "@iconify/react"; + +interface Props { + onClick: () => void | Promise; + text?: string; + className?: string; +} + +export default function SubmitButton({ onClick, text = "Submit", className }: Props) { + const [isLoading, setIsLoading] = useState(false); + + const handleClick = async (event: React.FormEvent) => { + event.preventDefault(); + + setIsLoading(true); + try { + await onClick(); + } finally { + setIsLoading(false); + } + }; + + return ( + + ); +} diff --git a/src/components/submit-form/edit-form.tsx b/src/components/submit-form/edit-form.tsx index b942941..6e2f6f4 100644 --- a/src/components/submit-form/edit-form.tsx +++ b/src/components/submit-form/edit-form.tsx @@ -13,6 +13,7 @@ import TagSelector from "../tag-selector"; import ImageList from "./image-list"; import LikeButton from "../like-button"; import Carousel from "../carousel"; +import SubmitButton from "../submit-button"; interface Props { mii: Mii; @@ -46,9 +47,7 @@ export default function EditForm({ mii, likes }: Props) { const [tags, setTags] = useState(mii.tags); const hasFilesChanged = useRef(false); - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - + const handleSubmit = async () => { // Validate before sending request const nameValidation = nameSchema.safeParse(name); if (!nameValidation.success) { @@ -110,7 +109,7 @@ export default function EditForm({ mii, likes }: Props) { }, [mii.id, mii.imageCount]); return ( -
+
URL.createObjectURL(file))]} /> @@ -201,9 +200,7 @@ export default function EditForm({ mii, likes }: Props) {
{error && Error: {error}} - +
diff --git a/src/components/submit-form/index.tsx b/src/components/submit-form/index.tsx index 9937b63..be94d99 100644 --- a/src/components/submit-form/index.tsx +++ b/src/components/submit-form/index.tsx @@ -19,6 +19,7 @@ import QrUpload from "./qr-upload"; import QrScanner from "./qr-scanner"; import LikeButton from "../like-button"; import Carousel from "../carousel"; +import SubmitButton from "../submit-button"; export default function SubmitForm() { const [files, setFiles] = useState([]); @@ -49,9 +50,7 @@ export default function SubmitForm() { const [tags, setTags] = useState([]); const [qrBytesRaw, setQrBytesRaw] = useState([]); - const handleSubmit = async (event: React.FormEvent) => { - event.preventDefault(); - + const handleSubmit = async () => { // Validate before sending request const nameValidation = nameSchema.safeParse(name); if (!nameValidation.success) { @@ -129,7 +128,7 @@ export default function SubmitForm() { }, [qrBytesRaw]); return ( -
+
{error && Error: {error}} - +
diff --git a/src/components/username-form.tsx b/src/components/username-form.tsx index 802c5b1..3132434 100644 --- a/src/components/username-form.tsx +++ b/src/components/username-form.tsx @@ -1,16 +1,15 @@ "use client"; -import { FormEvent, useState } from "react"; +import { useState } from "react"; import { redirect } from "next/navigation"; import { usernameSchema } from "@/lib/schemas"; +import SubmitButton from "./submit-button"; export default function UsernameForm() { const [username, setUsername] = useState(""); const [error, setError] = useState(undefined); - const handleSubmit = async (event: FormEvent) => { - event.preventDefault(); - + const handleSubmit = async () => { const parsed = usernameSchema.safeParse(username); if (!parsed.success) setError(parsed.error.errors[0].message); @@ -30,7 +29,7 @@ export default function UsernameForm() { }; return ( -
+ - + {error &&

Error: {error}

} );