adds user accounts, service requests, dashboard, admin panel, better layout, db+altcha+auth support
This commit is contained in:
parent
dfbc3cade9
commit
0043a5bf3c
40 changed files with 3981 additions and 188 deletions
57
components/core/altcha.tsx
Normal file
57
components/core/altcha.tsx
Normal file
|
@ -0,0 +1,57 @@
|
|||
"use client"
|
||||
|
||||
import { useEffect, useRef, useState, forwardRef, useImperativeHandle } from 'react'
|
||||
|
||||
interface AltchaProps {
|
||||
onStateChange?: (ev: Event | CustomEvent) => void
|
||||
}
|
||||
|
||||
const Altcha = forwardRef<{ value: string | null }, AltchaProps>(({ onStateChange }, ref) => {
|
||||
const widgetRef = useRef<AltchaWidget & AltchaWidgetMethods & HTMLElement>(null)
|
||||
const [value, setValue] = useState<string | null>(null)
|
||||
|
||||
useEffect(() => {
|
||||
import('altcha')
|
||||
}, [])
|
||||
|
||||
useImperativeHandle(ref, () => {
|
||||
return {
|
||||
get value() {
|
||||
return value
|
||||
}
|
||||
}
|
||||
}, [value])
|
||||
|
||||
useEffect(() => {
|
||||
const handleStateChange = (ev: Event | CustomEvent) => {
|
||||
if ('detail' in ev) {
|
||||
setValue(ev.detail.payload || null)
|
||||
onStateChange?.(ev)
|
||||
}
|
||||
}
|
||||
|
||||
const { current } = widgetRef
|
||||
|
||||
if (current) {
|
||||
current.addEventListener('statechange', handleStateChange)
|
||||
return () => current.removeEventListener('statechange', handleStateChange)
|
||||
}
|
||||
}, [onStateChange])
|
||||
|
||||
return (
|
||||
<altcha-widget
|
||||
challengeurl="/api/captcha"
|
||||
ref={widgetRef}
|
||||
style={{
|
||||
'--altcha-max-width': '100%',
|
||||
}}
|
||||
debug={process.env.NODE_ENV === "development"}
|
||||
aria-label="Security check"
|
||||
aria-describedby="altcha-description"
|
||||
></altcha-widget>
|
||||
)
|
||||
})
|
||||
|
||||
Altcha.displayName = 'Altcha'
|
||||
|
||||
export default Altcha
|
|
@ -1,6 +1,36 @@
|
|||
"use client"
|
||||
|
||||
import Link from "next/link";
|
||||
import { authClient } from "@/util/auth-client";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
interface ExtendedUser {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
emailVerified: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
image?: string | null;
|
||||
role?: string;
|
||||
}
|
||||
|
||||
export function Nav() {
|
||||
const { data: session, isPending } = authClient.useSession();
|
||||
const router = useRouter();
|
||||
|
||||
const handleSignOut = async () => {
|
||||
try {
|
||||
await fetch("/api/logout", {
|
||||
method: "POST",
|
||||
});
|
||||
await authClient.signOut();
|
||||
router.refresh();
|
||||
} catch (error) {
|
||||
console.error("Sign out error:", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col sm:flex-row items-center justify-between px-4 sm:px-5 py-3 gap-3 sm:gap-0">
|
||||
<Link href="/">
|
||||
|
@ -13,6 +43,31 @@ export function Nav() {
|
|||
<Link href="/about" className="hover:underline">About</Link>
|
||||
<Link href="/servers" className="hover:underline">Servers</Link>
|
||||
<Link href="/services" className="hover:underline">Services</Link>
|
||||
{isPending ? (
|
||||
<div className="text-gray-500">Loading...</div>
|
||||
) : session ? (
|
||||
<div className="flex items-center gap-3">
|
||||
<Link href="/dashboard" className="hover:underline">Dashboard</Link>
|
||||
<Link href="/requests" className="hover:underline">Requests</Link>
|
||||
{(session.user as ExtendedUser).role === 'admin' && (
|
||||
<Link href="/admin" className="hover:underline text-red-500">Admin</Link>
|
||||
)}
|
||||
<span className="text-foreground-muted-light ml-6">Hi, <span className="font-bold text-foreground">{session.user.name || session.user.email}</span></span>
|
||||
<button
|
||||
onClick={handleSignOut}
|
||||
className="text-red-400 hover:underline cursor-pointer"
|
||||
>
|
||||
Sign Out
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center gap-3">
|
||||
<Link href="/login" className="hover:underline">Login</Link>
|
||||
<Link href="/signup" className="bg-blue-400 text-white px-3 py-1 rounded-md hover:bg-blue-500">
|
||||
Sign Up
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue