"use client" import type React from "react" import { useState, useEffect, useRef } from "react" import { Card, CardContent, CardHeader, CardFooter, CardTitle, CardDescription } from "@/components/ui/card" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Button } from "@/components/ui/button" import { Switch } from "@/components/ui/switch" import Link from "next/link" import { motion, AnimatePresence } from "motion/react" import { UserPlus, UserCog, Heart, AlertCircle, CheckCircle2, Mail, Lock, User, Bot, Loader, ArrowLeft } from "lucide-react" import { useRouter } from "next/navigation" import { validateEmail, validatePassword } from "@/lib/utils" import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert" import EmailField from "@/components/custom/signup/EmailField" import Turnstile from "@/components/custom/Turnstile" declare global { interface Window { onTurnstileSuccess?: (token: string) => void onloadTurnstileCallback?: () => void } } export default function Signup() { const router = useRouter() const [formType, setFormType] = useState<"initial" | "create" | "migrate">("initial") const [formData, setFormData] = useState({ name: "", emailUsername: "", emailDomain: "librecloud.cc", password: "", terms: false, migratePassword: "", migrateTerms: false, migrateName: "", }) const [isValid, setIsValid] = useState(false) const [validationMessage, setValidationMessage] = useState("") const [isSubmitting, setIsSubmitting] = useState(false) const [turnstileStatus, setTurnstileStatus] = useState<"success" | "error" | "expired" | "required">("required") const formRef = useRef(null) const [errorAlert, setErrorAlert] = useState(null) const [forceRefresh, setForceRefresh] = useState(false) const fadeInOut = { initial: { opacity: 0, y: 20 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: -20 }, transition: { duration: 0.3 }, } const handleSelectChange = (value: string) => { setFormData((prev) => ({ ...prev, emailDomain: value })) if (errorAlert) setErrorAlert(null) } const handleInputChange = (e: React.ChangeEvent) => { const { name, value, type, checked } = e.target setFormData((prev) => ({ ...prev, [name]: type === "checkbox" ? checked : value, })) if (errorAlert) { setErrorAlert(null) } } const turnstileCallback = () => { console.log("[i] Turnstile token received") } useEffect(() => { window.onTurnstileSuccess = turnstileCallback return () => { delete window.onTurnstileSuccess } }, []) useEffect(() => { if (formType === "create") { const { name, emailUsername, emailDomain, password, terms } = formData if (name.length < 2) { setIsValid(false) setValidationMessage("Enter your name") return } const emailValidation = validateEmail(emailUsername, emailDomain) if (!emailValidation.valid) { setIsValid(false) setValidationMessage(emailValidation.message) return } const passwordValidation = validatePassword(password) if (!passwordValidation.valid) { setIsValid(false) setValidationMessage(passwordValidation.message) return } if (!terms) { setIsValid(false) setValidationMessage("Accept the terms") return } if (turnstileStatus !== "success") { setIsValid(false) setValidationMessage("Please verify you are not a robot") return } setIsValid(true) setValidationMessage("Create Account") } else if (formType === "migrate") { const { emailUsername, emailDomain, migratePassword, migrateTerms, migrateName } = formData if (migrateName.length < 2) { setIsValid(false) setValidationMessage("Enter your name") return } const emailValidation = validateEmail(emailUsername, emailDomain) if (!emailValidation.valid) { setIsValid(false) setValidationMessage(emailValidation.message) return } const passwordValidation = validatePassword(migratePassword) if (!passwordValidation.valid) { setIsValid(false) setValidationMessage(passwordValidation.message) return } if (!migrateTerms) { setIsValid(false) setValidationMessage("Accept the terms") return } if (turnstileStatus !== "success") { setIsValid(false) setValidationMessage("Please verify you are not a robot") return } setIsValid(true) setValidationMessage("Migrate Account") } }, [formData, formType, turnstileStatus]) const getButtonIcon = () => { if (isValid) return if (validationMessage.includes("name")) return if (validationMessage.includes("Email") || validationMessage.includes("email")) return if (validationMessage.includes("Password") || validationMessage.includes("password")) return if (validationMessage.includes("terms")) return if (validationMessage.includes("robot") || validationMessage.includes("Security")) return return null } const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() setIsSubmitting(true) setErrorAlert(null) try { if (turnstileStatus !== "success") { setValidationMessage("Please verify you are not a robot") setIsSubmitting(false) return } const email = `${formData.emailUsername}@${formData.emailDomain}` const formDataObj = new FormData(formRef.current as HTMLFormElement) const token = formDataObj.get("cf-turnstile-response") as string if (!token) { setErrorAlert("Cloudflare Turnstile token is missing. Please refresh") setIsSubmitting(false) setForceRefresh(true) return } const response = await fetch("/api/users/create", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ name: formType === "create" ? formData.name : formData.migrateName, email: email, password: formType === "create" ? formData.password : formData.migratePassword, migrate: formType === "migrate", token: token, }), }) const data = await response.json() if (!response.ok) { console.error("[!] API error:", response.status, data) setErrorAlert(data.message || `Error ${response.status}: Failed to create account`) setIsSubmitting(false) setForceRefresh(true) return } if (data.success) { router.push("/account/signup/success") } else { setErrorAlert(data.message || "Failed to create account.") } } catch (error) { console.error("[!] Form submission error:", error) setErrorAlert("An unexpected error occurred. Please try again later.") } finally { setIsSubmitting(false) } } return (
Account Setup Create a new account or migrate an existing one. {errorAlert && ( Oops! Something went wrong. {errorAlert} )} {formType === "initial" && ( )} {formType === "create" && (

A username for Authentik will be generated based on your email. Contact support if a username isn't available.

Password must be 8-128 characters long, include letters and digits, and not contain spaces.

{ setFormData((prev) => ({ ...prev, terms: checked })) if (errorAlert) setErrorAlert(null) }} />
{!forceRefresh && ( )}
)} {formType === "migrate" && (

A username for Authentik will be generated based on your email. Contact support if a username isn't available.

Password must be 8-64 characters long, include letters and digits, and not contain spaces.

{ setFormData((prev) => ({ ...prev, migrateTerms: checked })) if (errorAlert) setErrorAlert(null) }} />
{!forceRefresh && ( )}
)}
{!forceRefresh ? ( formType !== "initial" ? ( ) : ( Welcome to the LibreCloud family! ) ) : ( )}
) }