wulf-pulse/app/auth/verify/page.tsx
root 9f912aed24 feat: add authentication, user management, and admin features
Added comprehensive authentication and authorization system:

Authentication System:
- Better Auth integration with session management
- Login/logout pages and API routes
- Middleware for route protection
- Auth utilities and client libraries

User Management:
- User list, detail, and invite pages
- User API endpoints (CRUD operations)
- Session management for users
- Profile settings page

Role-Based Access Control:
- Role management pages (list, create, edit)
- Permission system with granular controls
- Role assignment to users
- Role API endpoints

Admin Features:
- Audit log page for tracking system events
- Admin settings page
- Audit service for logging user actions

Additional Features:
- Quotes management pages and components
- SalesBldr API integration
- Email service for notifications

Configuration & Documentation:
- Updated docker-compose.yml
- MCP server configuration (mcp.json)
- CVE-2025-55182 security review documentation
- Standards guide and PRD documents
- Re-enabling authentication documentation

Database Migrations:
- 012: Auth tables (users, sessions, accounts, verifications)
- 013: Role tables (roles, permissions, role_permissions, user_roles)
- 014: Admin settings table

UI Updates:
- Updated dashboard layout
- Enhanced app layout with auth integration
2026-01-31 12:43:14 -05:00

94 lines
3.3 KiB
TypeScript

"use client";
import { Suspense, useEffect, useState } from "react";
import { useSearchParams, useRouter } from "next/navigation";
import { Loader2, CheckCircle, XCircle } from "lucide-react";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
function VerifyContent() {
const searchParams = useSearchParams();
const router = useRouter();
const [status, setStatus] = useState<"loading" | "success" | "error">("loading");
const [errorMessage, setErrorMessage] = useState("");
useEffect(() => {
const token = searchParams.get("token");
const error = searchParams.get("error");
if (error) {
setStatus("error");
setErrorMessage(decodeURIComponent(error));
return;
}
if (!token) {
setStatus("error");
setErrorMessage("No verification token provided");
return;
}
// The verification is handled by Better Auth automatically
// If we reach this page with a token, it means the verification was successful
// and the user should be redirected
const callbackUrl = searchParams.get("callbackURL") || "/";
// Short delay to show success state
setTimeout(() => {
setStatus("success");
setTimeout(() => {
router.push(callbackUrl);
}, 1500);
}, 500);
}, [searchParams, router]);
return (
<Card className="border-0 shadow-2xl bg-white/95 dark:bg-slate-900/95 backdrop-blur">
<CardHeader className="space-y-1 text-center">
<div className="flex justify-center mb-4">
<div className="h-12 w-12 rounded-xl bg-gradient-to-br from-purple-600 to-blue-600 flex items-center justify-center">
<span className="text-2xl font-bold text-white">P</span>
</div>
</div>
<CardTitle className="text-2xl font-bold">
{status === "loading" && "Verifying..."}
{status === "success" && "Verified!"}
{status === "error" && "Verification Failed"}
</CardTitle>
<CardDescription>
{status === "loading" && "Please wait while we verify your magic link"}
{status === "success" && "You're being redirected..."}
{status === "error" && errorMessage}
</CardDescription>
</CardHeader>
<CardContent className="flex justify-center py-8">
{status === "loading" && (
<Loader2 className="h-12 w-12 animate-spin text-purple-600" />
)}
{status === "success" && (
<div className="h-16 w-16 rounded-full bg-green-100 dark:bg-green-900/30 flex items-center justify-center">
<CheckCircle className="h-8 w-8 text-green-600 dark:text-green-400" />
</div>
)}
{status === "error" && (
<div className="space-y-4 text-center">
<div className="h-16 w-16 rounded-full bg-red-100 dark:bg-red-900/30 flex items-center justify-center mx-auto">
<XCircle className="h-8 w-8 text-red-600 dark:text-red-400" />
</div>
<Button onClick={() => router.push("/auth/sign-in")}>
Try again
</Button>
</div>
)}
</CardContent>
</Card>
);
}
export default function VerifyPage() {
return (
<Suspense fallback={<div>Loading...</div>}>
<VerifyContent />
</Suspense>
);
}