cozynet/src/app/signup/page.tsx

252 lines
6.8 KiB
TypeScript

"use client"
import { useRouter } from "next/navigation"
import axios from "axios"
import Link from "next/link"
import { toast, ToastContainer } from "react-toastify"
import "react-toastify/dist/ReactToastify.css"
import { z, ZodError } from "zod" // Import Zod for input validation
import { Input } from "@/components/ui/input"
import { ApiFetch } from "@/lib/api"
// Define the Zod schema for signup form data
const signupSchema = z.object({
email: z.string().email(),
accessCode: z.string().min(20),
username: z.string().min(3).max(20),
password: z.string().min(6).max(30),
})
// InputField component
interface InputFieldProps {
id: string
type: string
name: string
labelText: string
placeholder: string
required: boolean
className?: string
}
const InputField: React.FC<InputFieldProps> = ({
id,
type,
name,
labelText,
placeholder,
required,
className,
}) => (
<div>
<label htmlFor={id} className="text-text mb-2 block text-sm font-medium">
{labelText}
</label>
<input
type={type}
id={id}
name={name}
placeholder={placeholder}
required={required}
className={`w-full rounded-md border px-4 py-2 ${className}`}
/>
</div>
)
// Signup component
export default function Signup() {
const { push } = useRouter() // Use push instead of replace
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault()
try {
const formValues = {
email: event.currentTarget.email.value,
accessCode: event.currentTarget.accessCode.value,
username: event.currentTarget.username.value,
password: event.currentTarget.password.value,
}
// Validate form data using Zod
signupSchema.parse(formValues);
const response = await ApiFetch(
"/SDHD/registerUser",
{
method: "POST",
body: JSON.stringify(formValues),
headers: {
"Content-Type": "application/json",
},
},
false,
true,
);
if (response.statusCode !== 200) {
return;
}
// Display success toast and redirect
toast.success("Signup successful!", {
className: "success-toast",
bodyClassName: "toast-body",
closeButton: false,
theme: "colored",
});
push("/chunithm")
} catch (error) {
handleSignUpError(error)
}
}
// Handle signup errors
function handleSignUpError(error: any) {
if (error instanceof ZodError) {
// Zod validation error
toast.error("Invalid signup data, please check the form.", {
className: "error-toast",
bodyClassName: "toast-body",
closeButton: false,
theme: "colored",
})
} else if (axios.isAxiosError(error)) {
// Other Axios errors
if (error.response && error.response.status === 404) {
toast.error(
"Please play at least one credit before signing in to the web UI",
{
className: "error-toast",
bodyClassName: "toast-body",
closeButton: false,
theme: "colored",
},
)
}
if (error.response && error.response.status === 500) {
toast.error("Username, email, or password already exists", {
className: "error-toast",
bodyClassName: "toast-body",
closeButton: false,
theme: "colored",
})
}
if (error.response && error.response.status === 409) {
toast.error(
"Cannot change username, email, or password during sign-up or rival_code is already taken",
{
className: "error-toast",
bodyClassName: "toast-body",
closeButton: false,
theme: "colored",
},
)
}
}
}
// Render the Signup form
return (
<main>
<div className="flex min-h-screen items-center justify-center bg-background px-6">
<div className="w-full max-w-md">
<div className="overflow-hidden rounded-sm bg-subsectionbackgroundcolor">
<div className="px-10 py-8">
<div className="mb-8 text-center">
<h1 className="text-2xl font-semibold text-typography">
USER SIGNUP
</h1>
</div>
<form onSubmit={handleSubmit} className="space-y-6">
<Input
id="email"
type="email"
name="email"
placeholder="Enter your email"
required={true}
className=""
/>
<Input
id="accessCode"
type="text"
name="accessCode"
placeholder="Enter your access code"
required={true}
className=""
/>
<Input
id="username"
type="text"
name="username"
placeholder="Enter your username"
required={true}
className=""
/>
<Input
id="password"
type="password"
name="password"
placeholder="Enter your password"
required={true}
className=""
/>
<div className="px-10 py-4 text-center">
<button
type="submit"
className="text-text cursor-pointer text-sm font-bold uppercase hover:underline"
>
Sign up
</button>
</div>
</form>
</div>
<div className="px-10 py-4 text-center">
<Link
href="/"
className="text-text start cursor-pointer text-sm font-bold uppercase hover:underline"
>
Already have an account? Login
</Link>
</div>
<ToastContainer
position="top-center"
autoClose={5000}
hideProgressBar={false}
newestOnTop={false}
closeOnClick
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover
limit={3}
toastClassName="toast-class"
/>
</div>
</div>
</div>
<style jsx>{`
.toast-class {
background-color: #2a2a2a;
color: white;
border-radius: 8px;
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
}
.success-toast {
background-color: #4caf50;
}
.error-toast {
background-color: #f44336;
}
.toast-body {
font-size: 0.9rem;
padding: 15px;
}
`}</style>
</main>
)
}