mirror of
https://github.com/LukeHagar/better-auth.git
synced 2025-12-10 04:19:32 +00:00
chore(demo): replace isLoading using useTransition (#3775)
* fix: use `useTransition` for isLoading * fixup! fix: use `useTransition` for isLoading
This commit is contained in:
committed by
Bereket Engida
parent
f49a2fbf99
commit
3ee67fcca0
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useState, useTransition } from "react";
|
||||||
import { signIn, client } from "@/lib/auth-client";
|
import { signIn, client } from "@/lib/auth-client";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
@@ -19,33 +19,31 @@ import { Loader2 } from "lucide-react";
|
|||||||
export default function ClientTest() {
|
export default function ClientTest() {
|
||||||
const [email, setEmail] = useState("");
|
const [email, setEmail] = useState("");
|
||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, startTransition] = useTransition();
|
||||||
|
|
||||||
// Get the session data using the useSession hook
|
// Get the session data using the useSession hook
|
||||||
const { data: session, isPending, error } = client.useSession();
|
const { data: session, isPending, error } = client.useSession();
|
||||||
|
|
||||||
const handleLogin = async () => {
|
const handleLogin = async () => {
|
||||||
setLoading(true);
|
startTransition(async () => {
|
||||||
await signIn.email(
|
await signIn.email(
|
||||||
{
|
{
|
||||||
email,
|
email,
|
||||||
password,
|
password,
|
||||||
callbackURL: "/client-test",
|
callbackURL: "/client-test",
|
||||||
},
|
|
||||||
{
|
|
||||||
onResponse: () => {
|
|
||||||
setLoading(false);
|
|
||||||
},
|
},
|
||||||
onError: (ctx) => {
|
{
|
||||||
toast.error(ctx.error.message);
|
onError: (ctx) => {
|
||||||
|
toast.error(ctx.error.message);
|
||||||
|
},
|
||||||
|
onSuccess: () => {
|
||||||
|
toast.success("Successfully logged in!");
|
||||||
|
setEmail("");
|
||||||
|
setPassword("");
|
||||||
|
},
|
||||||
},
|
},
|
||||||
onSuccess: () => {
|
);
|
||||||
toast.success("Successfully logged in!");
|
});
|
||||||
setEmail("");
|
|
||||||
setPassword("");
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ import {
|
|||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { useState } from "react";
|
import { useState, useTransition } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { UAParser } from "ua-parser-js";
|
import { UAParser } from "ua-parser-js";
|
||||||
import {
|
import {
|
||||||
@@ -657,7 +657,7 @@ function EditUserDialog() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
const [open, setOpen] = useState<boolean>(false);
|
const [open, setOpen] = useState<boolean>(false);
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
const [isLoading, startTransition] = useTransition();
|
||||||
return (
|
return (
|
||||||
<Dialog open={open} onOpenChange={setOpen}>
|
<Dialog open={open} onOpenChange={setOpen}>
|
||||||
<DialogTrigger asChild>
|
<DialogTrigger asChild>
|
||||||
@@ -720,25 +720,27 @@ function EditUserDialog() {
|
|||||||
<Button
|
<Button
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
setIsLoading(true);
|
startTransition(async () => {
|
||||||
await client.updateUser({
|
await client.updateUser({
|
||||||
image: image ? await convertImageToBase64(image) : undefined,
|
image: image ? await convertImageToBase64(image) : undefined,
|
||||||
name: name ? name : undefined,
|
name: name ? name : undefined,
|
||||||
fetchOptions: {
|
fetchOptions: {
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
toast.success("User updated successfully");
|
toast.success("User updated successfully");
|
||||||
|
},
|
||||||
|
onError: (error) => {
|
||||||
|
toast.error(error.error.message);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
});
|
||||||
toast.error(error.error.message);
|
startTransition(() => {
|
||||||
},
|
setName("");
|
||||||
},
|
router.refresh();
|
||||||
|
setImage(null);
|
||||||
|
setImagePreview(null);
|
||||||
|
setOpen(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
setName("");
|
|
||||||
router.refresh();
|
|
||||||
setImage(null);
|
|
||||||
setImagePreview(null);
|
|
||||||
setIsLoading(false);
|
|
||||||
setOpen(false);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Checkbox } from "@/components/ui/checkbox";
|
import { Checkbox } from "@/components/ui/checkbox";
|
||||||
import { useState } from "react";
|
import { useState, useTransition } from "react";
|
||||||
import { Loader2 } from "lucide-react";
|
import { Loader2 } from "lucide-react";
|
||||||
import { signIn } from "@/lib/auth-client";
|
import { signIn } from "@/lib/auth-client";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
@@ -22,7 +22,7 @@ import { useRouter } from "next/navigation";
|
|||||||
export default function SignIn() {
|
export default function SignIn() {
|
||||||
const [email, setEmail] = useState("");
|
const [email, setEmail] = useState("");
|
||||||
const [password, setPassword] = useState("");
|
const [password, setPassword] = useState("");
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, startTransition] = useTransition();
|
||||||
const [rememberMe, setRememberMe] = useState(false);
|
const [rememberMe, setRememberMe] = useState(false);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
@@ -83,16 +83,16 @@ export default function SignIn() {
|
|||||||
className="w-full"
|
className="w-full"
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
setLoading(true);
|
startTransition(async () => {
|
||||||
await signIn.email(
|
await signIn.email(
|
||||||
{ email, password, rememberMe: rememberMe ? true : false },
|
{ email, password, rememberMe },
|
||||||
{
|
{
|
||||||
onSuccess(context) {
|
onSuccess(context) {
|
||||||
router.push("/dashboard");
|
router.push("/dashboard");
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
);
|
||||||
);
|
});
|
||||||
setLoading(false);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{loading ? <Loader2 size={16} className="animate-spin" /> : "Login"}
|
{loading ? <Loader2 size={16} className="animate-spin" /> : "Login"}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { useState } from "react";
|
import { useState, useTransition } from "react";
|
||||||
import {
|
import {
|
||||||
Check,
|
Check,
|
||||||
Copy,
|
Copy,
|
||||||
@@ -50,11 +50,10 @@ export function useCopyButton(
|
|||||||
const cache = new Map<string, string>();
|
const cache = new Map<string, string>();
|
||||||
|
|
||||||
export function LLMCopyButton() {
|
export function LLMCopyButton() {
|
||||||
const [isLoading, setLoading] = useState(false);
|
const [isLoading, startTransition] = useTransition();
|
||||||
const [checked, onClick] = useCopyButton(async () => {
|
const [checked, onClick] = useCopyButton(async () => {
|
||||||
setLoading(true);
|
startTransition(async () => {
|
||||||
const url = window.location.pathname + ".mdx";
|
const url = window.location.pathname + ".mdx";
|
||||||
try {
|
|
||||||
const cached = cache.get(url);
|
const cached = cache.get(url);
|
||||||
|
|
||||||
if (cached) {
|
if (cached) {
|
||||||
@@ -71,9 +70,7 @@ export function LLMCopyButton() {
|
|||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
} finally {
|
});
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { useState } from "react";
|
import { useState, useTransition } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import * as z from "zod";
|
import * as z from "zod";
|
||||||
import { KJUR } from "jsrsasign";
|
import { KJUR } from "jsrsasign";
|
||||||
@@ -43,7 +43,7 @@ type AppleJwtFormValues = z.infer<typeof appleJwtSchema>;
|
|||||||
export const GenerateAppleJwt = () => {
|
export const GenerateAppleJwt = () => {
|
||||||
const [generatedJwt, setGeneratedJwt] = useState<string | null>(null);
|
const [generatedJwt, setGeneratedJwt] = useState<string | null>(null);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, startTransition] = useTransition();
|
||||||
|
|
||||||
const form = useForm<AppleJwtFormValues>({
|
const form = useForm<AppleJwtFormValues>({
|
||||||
resolver: zodResolver(appleJwtSchema),
|
resolver: zodResolver(appleJwtSchema),
|
||||||
@@ -56,48 +56,51 @@ export const GenerateAppleJwt = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const onSubmit = async (data: AppleJwtFormValues) => {
|
const onSubmit = async (data: AppleJwtFormValues) => {
|
||||||
setIsLoading(true);
|
|
||||||
setGeneratedJwt(null);
|
setGeneratedJwt(null);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
startTransition(() => {
|
||||||
|
try {
|
||||||
|
//normalize the private key by replacing \r\n with \n and trimming whitespace just incase lol
|
||||||
|
const normalizedKey = data.privateKey.replace(/\r\n/g, "\n").trim();
|
||||||
|
|
||||||
try {
|
//since jose is not working with safari, we are using jsrsasign
|
||||||
//normalize the private key by replacing \r\n with \n and trimming whitespace just incase lol
|
|
||||||
const normalizedKey = data.privateKey.replace(/\r\n/g, "\n").trim();
|
|
||||||
|
|
||||||
//since jose is not working with safari, we are using jsrsasign
|
const header = {
|
||||||
|
alg: "ES256",
|
||||||
|
kid: data.keyId,
|
||||||
|
typ: "JWT",
|
||||||
|
};
|
||||||
|
|
||||||
const header = {
|
const issuedAtSeconds = Math.floor(Date.now() / 1000);
|
||||||
alg: "ES256",
|
const expirationSeconds = issuedAtSeconds + 180 * 24 * 60 * 60; // 180 days. Should we let the user choose this ? MAX is 6 months
|
||||||
kid: data.keyId,
|
|
||||||
typ: "JWT",
|
|
||||||
};
|
|
||||||
|
|
||||||
const issuedAtSeconds = Math.floor(Date.now() / 1000);
|
const payload = {
|
||||||
const expirationSeconds = issuedAtSeconds + 180 * 24 * 60 * 60; // 180 days. Should we let the user choose this ? MAX is 6 months
|
iss: data.teamId, // Issuer (Team ID)
|
||||||
|
aud: "https://appleid.apple.com", // Audience
|
||||||
|
sub: data.clientId, // Subject (Client ID -> Service ID)
|
||||||
|
iat: issuedAtSeconds, // Issued At timestamp
|
||||||
|
exp: expirationSeconds, // Expiration timestamp
|
||||||
|
};
|
||||||
|
|
||||||
const payload = {
|
const sHeader = JSON.stringify(header);
|
||||||
iss: data.teamId, // Issuer (Team ID)
|
const sPayload = JSON.stringify(payload);
|
||||||
aud: "https://appleid.apple.com", // Audience
|
|
||||||
sub: data.clientId, // Subject (Client ID -> Service ID)
|
|
||||||
iat: issuedAtSeconds, // Issued At timestamp
|
|
||||||
exp: expirationSeconds, // Expiration timestamp
|
|
||||||
};
|
|
||||||
|
|
||||||
const sHeader = JSON.stringify(header);
|
const jwt = KJUR.jws.JWS.sign(
|
||||||
const sPayload = JSON.stringify(payload);
|
"ES256",
|
||||||
|
sHeader,
|
||||||
const jwt = KJUR.jws.JWS.sign("ES256", sHeader, sPayload, normalizedKey);
|
sPayload,
|
||||||
setGeneratedJwt(jwt);
|
normalizedKey,
|
||||||
} catch (err: any) {
|
);
|
||||||
console.error("JWT Generation Error:", err);
|
setGeneratedJwt(jwt);
|
||||||
setError(
|
} catch (err: any) {
|
||||||
`Failed to generate JWT: ${
|
console.error("JWT Generation Error:", err);
|
||||||
err.message || "Unknown error"
|
setError(
|
||||||
}. Check key format and details.`,
|
`Failed to generate JWT: ${
|
||||||
);
|
err.message || "Unknown error"
|
||||||
} finally {
|
}. Check key format and details.`,
|
||||||
setIsLoading(false);
|
);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const copyToClipboard = () => {
|
const copyToClipboard = () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user