Compare commits
No commits in common. "0efc186e946f9dcaf4359963b5ae91619b399226" and "14a7bf629adcda50fc12fbf22389f12d7afc7771" have entirely different histories.
0efc186e94
...
14a7bf629a
@ -12,10 +12,10 @@ import Link from "next/link"
|
|||||||
import { motion, AnimatePresence } from "framer-motion"
|
import { motion, AnimatePresence } from "framer-motion"
|
||||||
import { UserPlus, UserCog, Heart, AlertCircle, CheckCircle2, Mail, Lock, User, Bot, Loader, ArrowLeft } from "lucide-react"
|
import { UserPlus, UserCog, Heart, AlertCircle, CheckCircle2, Mail, Lock, User, Bot, Loader, ArrowLeft } from "lucide-react"
|
||||||
import { useRouter } from "next/navigation"
|
import { useRouter } from "next/navigation"
|
||||||
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||||||
|
import { Turnstile } from "next-turnstile"
|
||||||
import { validateEmail, validatePassword } from "@/lib/utils"
|
import { validateEmail, validatePassword } from "@/lib/utils"
|
||||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
|
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
|
||||||
import EmailField from "@/components/custom/signup/EmailField"
|
|
||||||
import Turnstile from "@/components/custom/Turnstile"
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Window {
|
interface Window {
|
||||||
@ -52,11 +52,6 @@ export default function Signup() {
|
|||||||
transition: { duration: 0.3 },
|
transition: { duration: 0.3 },
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleSelectChange = (value: string) => {
|
|
||||||
setFormData((prev) => ({ ...prev, emailDomain: value }))
|
|
||||||
if (errorAlert) setErrorAlert(null)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
const { name, value, type, checked } = e.target
|
const { name, value, type, checked } = e.target
|
||||||
setFormData((prev) => ({
|
setFormData((prev) => ({
|
||||||
@ -184,7 +179,7 @@ export default function Signup() {
|
|||||||
const token = formDataObj.get("cf-turnstile-response") as string
|
const token = formDataObj.get("cf-turnstile-response") as string
|
||||||
|
|
||||||
if (!token) {
|
if (!token) {
|
||||||
setErrorAlert("Cloudflare Turnstile token is missing. Please refresh")
|
setErrorAlert("Security verification token is missing. Please refresh")
|
||||||
setIsSubmitting(false)
|
setIsSubmitting(false)
|
||||||
setForceRefresh(true)
|
setForceRefresh(true)
|
||||||
return
|
return
|
||||||
@ -207,7 +202,7 @@ export default function Signup() {
|
|||||||
const data = await response.json()
|
const data = await response.json()
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
console.error("[!] API error:", response.status, data)
|
console.error("API error:", response.status, data)
|
||||||
setErrorAlert(data.message || `Error ${response.status}: Failed to create account`)
|
setErrorAlert(data.message || `Error ${response.status}: Failed to create account`)
|
||||||
setIsSubmitting(false)
|
setIsSubmitting(false)
|
||||||
setForceRefresh(true)
|
setForceRefresh(true)
|
||||||
@ -220,7 +215,7 @@ export default function Signup() {
|
|||||||
setErrorAlert(data.message || "Failed to create account.")
|
setErrorAlert(data.message || "Failed to create account.")
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("[!] Form submission error:", error)
|
console.error("Form submission error:", error)
|
||||||
setErrorAlert("An unexpected error occurred. Please try again later.")
|
setErrorAlert("An unexpected error occurred. Please try again later.")
|
||||||
} finally {
|
} finally {
|
||||||
setIsSubmitting(false)
|
setIsSubmitting(false)
|
||||||
@ -270,16 +265,42 @@ export default function Signup() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<EmailField
|
<Label htmlFor="email">Email</Label>
|
||||||
formData={formData}
|
<div className="flex items-center space-x-2">
|
||||||
errorAlert={errorAlert}
|
<Input
|
||||||
setErrorAlert={setErrorAlert}
|
id="emailUsername"
|
||||||
handleInputChange={handleInputChange}
|
name="emailUsername"
|
||||||
handleSelectChange={handleSelectChange}
|
type="text"
|
||||||
|
placeholder="username"
|
||||||
|
required
|
||||||
|
value={formData.emailUsername}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
className="grow"
|
||||||
/>
|
/>
|
||||||
<p className="text-xs text-muted-foreground">
|
<span className="text-muted-foreground">@</span>
|
||||||
A username for Authentik will be generated based on your email. <Link href="mailto:support@librecloud.cc" className="underline">Contact support</Link> if a username isn't available.
|
<Select
|
||||||
</p>
|
name="emailDomain"
|
||||||
|
value={formData.emailDomain}
|
||||||
|
onValueChange={(value) => {
|
||||||
|
setFormData((prev) => ({ ...prev, emailDomain: value }))
|
||||||
|
if (errorAlert) setErrorAlert(null)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="w-[180px]">
|
||||||
|
<SelectValue placeholder="Select domain" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="librecloud.cc">librecloud.cc</SelectItem>
|
||||||
|
<SelectItem value="pontusmail.org">pontusmail.org</SelectItem>
|
||||||
|
<SelectItem value="p0ntus.com">p0ntus.com</SelectItem>
|
||||||
|
<SelectItem value="ihate.college">ihate.college</SelectItem>
|
||||||
|
<SelectItem value="pontus.pics">pontus.pics</SelectItem>
|
||||||
|
<SelectItem value="dontbeevil.lol">dontbeevil.lol</SelectItem>
|
||||||
|
<SelectItem value="dont-be-evil.lol">dont-be-evil.lol</SelectItem>
|
||||||
|
<SelectItem value="strongintegrity.life">strongintegrity.life</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="password">Password</Label>
|
<Label htmlFor="password">Password</Label>
|
||||||
@ -320,8 +341,27 @@ export default function Signup() {
|
|||||||
</div>
|
</div>
|
||||||
{!forceRefresh && (
|
{!forceRefresh && (
|
||||||
<Turnstile
|
<Turnstile
|
||||||
setTurnstileStatus={setTurnstileStatus}
|
siteKey={process.env.NEXT_PUBLIC_CF_SITEKEY!}
|
||||||
setValidationMessage={setValidationMessage}
|
retry="auto"
|
||||||
|
refreshExpired="auto"
|
||||||
|
onError={() => {
|
||||||
|
setTurnstileStatus("error")
|
||||||
|
setValidationMessage("Security check failed. Please try again.")
|
||||||
|
console.error("[!] Turnstile error occurred")
|
||||||
|
}}
|
||||||
|
onExpire={() => {
|
||||||
|
setTurnstileStatus("expired")
|
||||||
|
setValidationMessage("Security check expired. Please verify again.")
|
||||||
|
console.warn("[!] Turnstile token expired")
|
||||||
|
}}
|
||||||
|
onLoad={() => {
|
||||||
|
setTurnstileStatus("required")
|
||||||
|
}}
|
||||||
|
onVerify={() => {
|
||||||
|
setTurnstileStatus("success")
|
||||||
|
console.log("[S] Turnstile verification successful")
|
||||||
|
}}
|
||||||
|
className="flex justify-center"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</motion.form>
|
</motion.form>
|
||||||
@ -340,13 +380,42 @@ export default function Signup() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<EmailField
|
<Label htmlFor="email">Email</Label>
|
||||||
formData={formData}
|
<div className="flex items-center space-x-2">
|
||||||
errorAlert={errorAlert}
|
<Input
|
||||||
setErrorAlert={setErrorAlert}
|
id="emailUsername"
|
||||||
handleInputChange={handleInputChange}
|
name="emailUsername"
|
||||||
handleSelectChange={handleSelectChange}
|
type="text"
|
||||||
|
placeholder="username"
|
||||||
|
required
|
||||||
|
value={formData.emailUsername}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
className="grow"
|
||||||
/>
|
/>
|
||||||
|
<span className="text-muted-foreground">@</span>
|
||||||
|
<Select
|
||||||
|
name="emailDomain"
|
||||||
|
value={formData.emailDomain}
|
||||||
|
onValueChange={(value) => {
|
||||||
|
setFormData((prev) => ({ ...prev, emailDomain: value }))
|
||||||
|
if (errorAlert) setErrorAlert(null)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="w-[180px]">
|
||||||
|
<SelectValue placeholder="Select domain" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="librecloud.cc">librecloud.cc</SelectItem>
|
||||||
|
<SelectItem value="pontusmail.org">pontusmail.org</SelectItem>
|
||||||
|
<SelectItem value="p0ntus.com">p0ntus.com</SelectItem>
|
||||||
|
<SelectItem value="ihate.college">ihate.college</SelectItem>
|
||||||
|
<SelectItem value="pontus.pics">pontus.pics</SelectItem>
|
||||||
|
<SelectItem value="dontbeevil.lol">dontbeevil.lol</SelectItem>
|
||||||
|
<SelectItem value="dont-be-evil.lol">dont-be-evil.lol</SelectItem>
|
||||||
|
<SelectItem value="strongintegrity.life">strongintegrity.life</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
A username for Authentik will be generated based on your email. <Link href="mailto:support@librecloud.cc" className="underline">Contact support</Link> if a username isn't available.
|
A username for Authentik will be generated based on your email. <Link href="mailto:support@librecloud.cc" className="underline">Contact support</Link> if a username isn't available.
|
||||||
</p>
|
</p>
|
||||||
@ -390,8 +459,27 @@ export default function Signup() {
|
|||||||
</div>
|
</div>
|
||||||
{!forceRefresh && (
|
{!forceRefresh && (
|
||||||
<Turnstile
|
<Turnstile
|
||||||
setTurnstileStatus={setTurnstileStatus}
|
siteKey={process.env.NEXT_PUBLIC_CF_SITEKEY!}
|
||||||
setValidationMessage={setValidationMessage}
|
retry="auto"
|
||||||
|
refreshExpired="auto"
|
||||||
|
onError={() => {
|
||||||
|
setTurnstileStatus("error")
|
||||||
|
setValidationMessage("Security check failed. Please try again.")
|
||||||
|
console.error("[!] Turnstile error occurred")
|
||||||
|
}}
|
||||||
|
onExpire={() => {
|
||||||
|
setTurnstileStatus("expired")
|
||||||
|
setValidationMessage("Security check expired. Please verify again.")
|
||||||
|
console.warn("[!] Turnstile token expired")
|
||||||
|
}}
|
||||||
|
onLoad={() => {
|
||||||
|
setTurnstileStatus("required")
|
||||||
|
}}
|
||||||
|
onVerify={() => {
|
||||||
|
setTurnstileStatus("success")
|
||||||
|
console.log("[S] Turnstile verification successful")
|
||||||
|
}}
|
||||||
|
className="flex justify-center"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</motion.form>
|
</motion.form>
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
import type React from "react"
|
|
||||||
import { Turnstile as CloudflareTS } from "next-turnstile"
|
|
||||||
|
|
||||||
interface TurnstileProps {
|
|
||||||
setTurnstileStatus: React.Dispatch<React.SetStateAction<"error" | "expired" | "required" | "success">>
|
|
||||||
setValidationMessage: (message: string) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Turnstile({ setTurnstileStatus, setValidationMessage }: TurnstileProps) {
|
|
||||||
return (
|
|
||||||
<CloudflareTS
|
|
||||||
siteKey={process.env.NEXT_PUBLIC_CF_SITEKEY!}
|
|
||||||
retry="auto"
|
|
||||||
refreshExpired="auto"
|
|
||||||
onError={() => {
|
|
||||||
setTurnstileStatus("error")
|
|
||||||
setValidationMessage("Security check failed. Please try again.")
|
|
||||||
console.error("[!] Turnstile error occurred")
|
|
||||||
}}
|
|
||||||
onExpire={() => {
|
|
||||||
setTurnstileStatus("expired")
|
|
||||||
setValidationMessage("Security check expired. Please verify again.")
|
|
||||||
console.warn("[!] Turnstile token expired")
|
|
||||||
}}
|
|
||||||
onLoad={() => {
|
|
||||||
setTurnstileStatus("required")
|
|
||||||
}}
|
|
||||||
onVerify={() => {
|
|
||||||
setTurnstileStatus("success")
|
|
||||||
console.log("[S] Turnstile verification successful")
|
|
||||||
}}
|
|
||||||
className="flex justify-center"
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
|||||||
import { Label } from "@/components/ui/label"
|
|
||||||
import { Input } from "@/components/ui/input"
|
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
|
||||||
import type React from "react"
|
|
||||||
|
|
||||||
interface EmailFieldProps {
|
|
||||||
formData: {
|
|
||||||
emailUsername: string
|
|
||||||
emailDomain: string
|
|
||||||
}
|
|
||||||
errorAlert: string | null
|
|
||||||
setErrorAlert: React.Dispatch<React.SetStateAction<string | null>>
|
|
||||||
handleInputChange: (e: React.ChangeEvent<HTMLInputElement>) => void
|
|
||||||
handleSelectChange: (value: string) => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function EmailField({ formData, handleInputChange, handleSelectChange }: EmailFieldProps) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<Label htmlFor="email">Email</Label>
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<Input
|
|
||||||
id="emailUsername"
|
|
||||||
name="emailUsername"
|
|
||||||
type="text"
|
|
||||||
placeholder="username"
|
|
||||||
required
|
|
||||||
value={formData.emailUsername}
|
|
||||||
onChange={handleInputChange}
|
|
||||||
className="grow"
|
|
||||||
/>
|
|
||||||
<span className="text-muted-foreground">@</span>
|
|
||||||
<Select
|
|
||||||
name="emailDomain"
|
|
||||||
value={formData.emailDomain}
|
|
||||||
onValueChange={handleSelectChange}
|
|
||||||
>
|
|
||||||
<SelectTrigger className="w-[180px]">
|
|
||||||
<SelectValue placeholder="Select domain" />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="librecloud.cc">librecloud.cc</SelectItem>
|
|
||||||
<SelectItem value="pontusmail.org">pontusmail.org</SelectItem>
|
|
||||||
<SelectItem value="p0ntus.com">p0ntus.com</SelectItem>
|
|
||||||
<SelectItem value="ihate.college">ihate.college</SelectItem>
|
|
||||||
<SelectItem value="pontus.pics">pontus.pics</SelectItem>
|
|
||||||
<SelectItem value="dontbeevil.lol">dontbeevil.lol</SelectItem>
|
|
||||||
<SelectItem value="dont-be-evil.lol">dont-be-evil.lol</SelectItem>
|
|
||||||
<SelectItem value="strongintegrity.life">strongintegrity.life</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user