change how the auth page looks and reset the captcha during auth failures
All checks were successful
Deploy / deploy (ubuntu-latest, 2.44.0) (push) Successful in 1m29s
All checks were successful
Deploy / deploy (ubuntu-latest, 2.44.0) (push) Successful in 1m29s
This commit is contained in:
parent
673bfb6fe7
commit
0e77042553
@ -38,13 +38,14 @@
|
|||||||
"zustand": "^5.0.0-rc.2"
|
"zustand": "^5.0.0-rc.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^5",
|
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
"@types/react": "^18",
|
"@types/react": "^18",
|
||||||
"@types/react-dom": "^18",
|
"@types/react-dom": "^18",
|
||||||
|
"eslint": "^8",
|
||||||
|
"eslint-config-next": "14.2.8",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
"tailwindcss": "^3.4.1",
|
"tailwindcss": "^3.4.1",
|
||||||
"eslint": "^8",
|
"turnstile-types": "^1.2.2",
|
||||||
"eslint-config-next": "14.2.8"
|
"typescript": "^5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,30 +19,29 @@ import { Cookies, useCookies } from "next-client-cookies";
|
|||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime";
|
import { AppRouterInstance } from "next/dist/shared/lib/app-router-context.shared-runtime";
|
||||||
import { motion } from "framer-motion";
|
import { motion } from "framer-motion";
|
||||||
import Turnstile from "react-turnstile";
|
import Turnstile, { useTurnstile } from "react-turnstile";
|
||||||
|
import { TurnstileObject } from "turnstile-types";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Define the form schemas for the various stages.
|
* Define the form schemas for the various stages.
|
||||||
*/
|
*/
|
||||||
const EmailSchema = z.object({
|
const EmailSchema = z.object({
|
||||||
email: z.string().email("Must be a valid email address"),
|
email: z.string().email("Must be a valid email address."),
|
||||||
});
|
});
|
||||||
|
|
||||||
const RegisterSchema = z.object({
|
const RegisterSchema = z.object({
|
||||||
email: z.string().email("Must be a valid email address"),
|
email: z.string().email("Must be a valid email address."),
|
||||||
username: z.string(),
|
username: z.string(),
|
||||||
password: z.string(),
|
password: z.string(),
|
||||||
passwordConfirmation: z.string(),
|
passwordConfirmation: z.string(),
|
||||||
// captchaResponse: z.string(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const LoginSchema = z.object({
|
const LoginSchema = z.object({
|
||||||
email: z.union([
|
email: z.union([
|
||||||
z.string().email("Must be a valid email address"),
|
z.string().email("Must be a valid email address."),
|
||||||
z.string({ message: "Must be a valid username" }),
|
z.string({ message: "Must be a valid username." }),
|
||||||
]),
|
]),
|
||||||
password: z.string(),
|
password: z.string(),
|
||||||
// captchaResponse: z.string(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -65,6 +64,7 @@ const AuthForm = (): ReactElement => {
|
|||||||
undefined
|
undefined
|
||||||
);
|
);
|
||||||
const [error, setError] = useState<string | undefined>(undefined);
|
const [error, setError] = useState<string | undefined>(undefined);
|
||||||
|
const turnstile: TurnstileObject = useTurnstile();
|
||||||
const cookies: Cookies = useCookies();
|
const cookies: Cookies = useCookies();
|
||||||
const router: AppRouterInstance = useRouter();
|
const router: AppRouterInstance = useRouter();
|
||||||
|
|
||||||
@ -118,7 +118,12 @@ const AuthForm = (): ReactElement => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
setError(error?.message ?? undefined);
|
setError(error?.message ?? undefined);
|
||||||
if (!error) {
|
|
||||||
|
// Reset the captcha if auth fails
|
||||||
|
if (error) {
|
||||||
|
turnstile.reset();
|
||||||
|
} else {
|
||||||
|
// Otherwise store the session and redirect to the dashboard
|
||||||
cookies.set("session", JSON.stringify(data), {
|
cookies.set("session", JSON.stringify(data), {
|
||||||
expires:
|
expires:
|
||||||
((data?.expires as number) - Date.now()) / 86_400_000,
|
((data?.expires as number) - Date.now()) / 86_400_000,
|
||||||
@ -212,21 +217,30 @@ const AuthForm = (): ReactElement => {
|
|||||||
onVerify={(token: string) => setCaptchaResponse(token)}
|
onVerify={(token: string) => setCaptchaResponse(token)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Errors */}
|
{/* Display the global error if it exists, otherwise show the first field error */}
|
||||||
{error && <p className="text-red-500">{error}</p>}
|
<p className="-mt-2 pb-0.5 text-red-500">
|
||||||
|
{error
|
||||||
|
? error
|
||||||
|
: Object.values(errors).find((err: any) => err?.message) &&
|
||||||
|
Object.values(errors)
|
||||||
|
.find((err: any) => err?.message)
|
||||||
|
?.message?.toString()}
|
||||||
|
</p>
|
||||||
|
|
||||||
{/* Submit Form */}
|
{/* Submit Form */}
|
||||||
<Button
|
<Button
|
||||||
className="h-11 flex gap-2 items-center bg-zinc-800/75 text-white border border-zinc-700/35 hover:bg-zinc-800/75 hover:opacity-75 transition-all transform-gpu group"
|
className="h-11 flex gap-2.5 items-center bg-zinc-800/75 text-white border border-zinc-700/35 hover:bg-zinc-800/75 hover:opacity-75 transition-all transform-gpu group"
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
>
|
>
|
||||||
{loading && <ArrowPathIcon className="w-4 h-4 animate-spin" />}
|
{loading && <ArrowPathIcon className="w-4 h-4 animate-spin" />}
|
||||||
{stage === "email"
|
<span className="-translate-y-0.5">
|
||||||
? "Continue"
|
{stage === "email"
|
||||||
: stage === "register"
|
? "Continue"
|
||||||
? "Register"
|
: stage === "register"
|
||||||
: "Login"}
|
? "Register"
|
||||||
|
: "Login"}
|
||||||
|
</span>
|
||||||
{!loading && <AnimatedRightChevron />}
|
{!loading && <AnimatedRightChevron />}
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user