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
99 lines
3.3 KiB
TypeScript
99 lines
3.3 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { useRouter } from "next/navigation";
|
|
import { Loader2, ShieldCheck } from "lucide-react";
|
|
import { toast } from "sonner";
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
|
import { Button } from "@/components/ui/button";
|
|
import { MicrosoftButton } from "@/components/auth/microsoft-button";
|
|
import { Separator } from "@/components/ui/separator";
|
|
import { authClient } from "@/lib/auth-client";
|
|
|
|
export default function SetupPage() {
|
|
const router = useRouter();
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
|
|
async function handleSendMagicLink() {
|
|
setIsLoading(true);
|
|
try {
|
|
// Get current user's email from session
|
|
const session = await authClient.getSession();
|
|
if (!session?.data?.user?.email) {
|
|
toast.error("Unable to get user email");
|
|
return;
|
|
}
|
|
|
|
const result = await authClient.signIn.magicLink({
|
|
email: session.data.user.email,
|
|
callbackURL: "/",
|
|
});
|
|
|
|
if (result.error) {
|
|
toast.error(result.error.message || "Failed to send magic link");
|
|
return;
|
|
}
|
|
|
|
toast.success("Magic link sent! Check your email to complete setup.");
|
|
} catch (error) {
|
|
toast.error("An unexpected error occurred");
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
}
|
|
|
|
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-amber-500 to-orange-600 flex items-center justify-center">
|
|
<ShieldCheck className="h-6 w-6 text-white" />
|
|
</div>
|
|
</div>
|
|
<CardTitle className="text-2xl font-bold">Complete Your Setup</CardTitle>
|
|
<CardDescription>
|
|
Your account was created by an administrator. Please link an authentication method to secure your account.
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-6">
|
|
<div className="bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 rounded-lg p-4">
|
|
<p className="text-sm text-amber-800 dark:text-amber-200">
|
|
This is a one-time setup. After completing this step, you'll be able to sign in normally.
|
|
</p>
|
|
</div>
|
|
|
|
{/* Microsoft OAuth */}
|
|
<MicrosoftButton callbackURL="/" />
|
|
|
|
{/* Divider */}
|
|
<div className="relative">
|
|
<div className="absolute inset-0 flex items-center">
|
|
<Separator className="w-full" />
|
|
</div>
|
|
<div className="relative flex justify-center text-xs uppercase">
|
|
<span className="bg-white dark:bg-slate-900 px-2 text-muted-foreground">
|
|
Or use email
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Magic Link */}
|
|
<Button
|
|
variant="outline"
|
|
className="w-full"
|
|
onClick={handleSendMagicLink}
|
|
disabled={isLoading}
|
|
>
|
|
{isLoading ? (
|
|
<>
|
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
Sending...
|
|
</>
|
|
) : (
|
|
"Send Magic Link to My Email"
|
|
)}
|
|
</Button>
|
|
</CardContent>
|
|
</Card>
|
|
);
|
|
}
|