"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, Loader2, ArrowLeft } from "lucide-react" import { useRouter } from "next/navigation" import { validateEmail, validatePassword, validateName } from "@/lib/utils" import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert" import EmailField from "@/components/custom/signup/EmailField" import Altcha from "@/components/custom/Altcha" import { useSession } from "next-auth/react" 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 [altchaStatus, setAltchaStatus] = useState<"success" | "error" | "expired" | "required">("required") const formRef = useRef(null) const [errorAlert, setErrorAlert] = useState(null) const [forceRefresh, setForceRefresh] = useState(false) const [altchaToken, setAltchaToken] = useState(null) 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 handleAltchaStateChange = (e: Event | CustomEvent) => { if ('detail' in e && e.detail?.payload) { setAltchaToken(e.detail.payload) setAltchaStatus("success") } else { setAltchaToken(null) setAltchaStatus("required") } } useEffect(() => { if (formType === "create") { const { name, emailUsername, emailDomain, password, terms } = formData const nameValidation = validateName(name) if (!nameValidation.valid) { setIsValid(false) setValidationMessage(nameValidation.message) 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 (altchaStatus !== "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 const nameValidation = validateName(migrateName) if (!nameValidation.valid) { setIsValid(false) setValidationMessage(nameValidation.message) 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 (altchaStatus !== "success") { setIsValid(false) setValidationMessage("Please verify you are not a robot") return } setIsValid(true) setValidationMessage("Migrate Account") } }, [formData, formType, altchaStatus]) const getButtonIcon = () => { if (isValid) return if (validationMessage.includes("name") || 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 if (validationMessage.includes("special characters")) return return null } const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() setIsSubmitting(true) setErrorAlert(null) try { if (altchaStatus !== "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("altcha-token") as string if (!token) { setErrorAlert("Altcha 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) } } const { data: session } = useSession() useEffect(() => { if (session) { router.push("/account/dashboard") } }, [session, router]) return (
{formType === "initial" ? ( Account Setup Create a new account or migrate an existing one. ) : formType === "create" ? ( Create New Account Set up your new LibreCloud account. ) : ( Migrate Account Transfer your p0ntus mail account to LibreCloud. )} {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 && ( )} {!forceRefresh && ( <>
A CAPTCHA box. You must solve the challenge to make an account.
)}
)} {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 && ( <>
A CAPTCHA box. You must solve the challenge to make an account.
)}
)}
{!forceRefresh ? ( formType !== "initial" ? ( ) : ( Welcome to the LibreCloud family! ) ) : ( )}
) }