Compare commits
2 Commits
14a7bf629a
...
0efc186e94
Author | SHA1 | Date | |
---|---|---|---|
0efc186e94 | |||
1e6e583a5b |
@ -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,6 +52,11 @@ 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) => ({
|
||||||
@ -179,7 +184,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("Security verification token is missing. Please refresh")
|
setErrorAlert("Cloudflare Turnstile token is missing. Please refresh")
|
||||||
setIsSubmitting(false)
|
setIsSubmitting(false)
|
||||||
setForceRefresh(true)
|
setForceRefresh(true)
|
||||||
return
|
return
|
||||||
@ -202,7 +207,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)
|
||||||
@ -215,7 +220,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)
|
||||||
@ -265,42 +270,16 @@ export default function Signup() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="email">Email</Label>
|
<EmailField
|
||||||
<div className="flex items-center space-x-2">
|
formData={formData}
|
||||||
<Input
|
errorAlert={errorAlert}
|
||||||
id="emailUsername"
|
setErrorAlert={setErrorAlert}
|
||||||
name="emailUsername"
|
handleInputChange={handleInputChange}
|
||||||
type="text"
|
handleSelectChange={handleSelectChange}
|
||||||
placeholder="username"
|
/>
|
||||||
required
|
<p className="text-xs text-muted-foreground">
|
||||||
value={formData.emailUsername}
|
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.
|
||||||
onChange={handleInputChange}
|
</p>
|
||||||
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>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="password">Password</Label>
|
<Label htmlFor="password">Password</Label>
|
||||||
@ -341,27 +320,8 @@ export default function Signup() {
|
|||||||
</div>
|
</div>
|
||||||
{!forceRefresh && (
|
{!forceRefresh && (
|
||||||
<Turnstile
|
<Turnstile
|
||||||
siteKey={process.env.NEXT_PUBLIC_CF_SITEKEY!}
|
setTurnstileStatus={setTurnstileStatus}
|
||||||
retry="auto"
|
setValidationMessage={setValidationMessage}
|
||||||
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>
|
||||||
@ -380,42 +340,13 @@ export default function Signup() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="email">Email</Label>
|
<EmailField
|
||||||
<div className="flex items-center space-x-2">
|
formData={formData}
|
||||||
<Input
|
errorAlert={errorAlert}
|
||||||
id="emailUsername"
|
setErrorAlert={setErrorAlert}
|
||||||
name="emailUsername"
|
handleInputChange={handleInputChange}
|
||||||
type="text"
|
handleSelectChange={handleSelectChange}
|
||||||
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>
|
||||||
@ -459,27 +390,8 @@ export default function Signup() {
|
|||||||
</div>
|
</div>
|
||||||
{!forceRefresh && (
|
{!forceRefresh && (
|
||||||
<Turnstile
|
<Turnstile
|
||||||
siteKey={process.env.NEXT_PUBLIC_CF_SITEKEY!}
|
setTurnstileStatus={setTurnstileStatus}
|
||||||
retry="auto"
|
setValidationMessage={setValidationMessage}
|
||||||
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>
|
||||||
|
36
components/custom/Turnstile.tsx
Normal file
36
components/custom/Turnstile.tsx
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
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"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
56
components/custom/signup/EmailField.tsx
Normal file
56
components/custom/signup/EmailField.tsx
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
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