forked from PolarisPyra/cozynet
252 lines
6.8 KiB
TypeScript
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>
|
|
)
|
|
}
|