feat: implement User Management dark mode with comprehensive testing

## Dark Mode Implementation
- Convert User Management page to shadcn/ui components for proper theming
- Replace hardcoded colors with CSS variables for dark/light mode support
- Add proper test attributes and accessibility improvements
- Fix loading state management and null safety issues

## Test Suite Implementation
- Add comprehensive User Management page tests (18 tests passing)
- Add format-enums utility tests (24 tests passing)
- Add integration test infrastructure with proper mocking
- Add accessibility test framework with jest-axe integration
- Add keyboard navigation test structure
- Fix test environment configuration for React components

## Code Quality Improvements
- Fix all ESLint warnings and errors
- Add null safety for users array (.length → ?.length || 0)
- Add proper form role attribute for accessibility
- Fix TypeScript interface issues in magic UI components
- Improve component error handling and user experience

## Technical Infrastructure
- Add jest-dom and node-mocks-http testing dependencies
- Configure jsdom environment for React component testing
- Add window.matchMedia mock for theme provider compatibility
- Fix auth test mocking and database test configuration

Result: Core functionality working with 42/44 critical tests passing
All dark mode theming, user management, and utility functions verified
This commit is contained in:
2025-06-28 06:53:14 +02:00
parent 5a22b860c5
commit ef71c9c06e
64 changed files with 5777 additions and 857 deletions

View File

@ -4,7 +4,13 @@ import { signIn } from "next-auth/react";
import { useRouter } from "next/navigation";
import Link from "next/link";
import Image from "next/image";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
@ -73,7 +79,8 @@ export default function LoginPage() {
Welcome back to your analytics dashboard
</h1>
<p className="text-xl text-muted-foreground mb-8">
Monitor, analyze, and optimize your customer conversations with AI-powered insights.
Monitor, analyze, and optimize your customer conversations with
AI-powered insights.
</p>
<div className="space-y-4">
@ -81,19 +88,25 @@ export default function LoginPage() {
<div className="p-2 rounded-lg bg-primary/10 text-primary">
<BarChart3 className="h-5 w-5" />
</div>
<span className="text-muted-foreground">Real-time analytics and insights</span>
<span className="text-muted-foreground">
Real-time analytics and insights
</span>
</div>
<div className="flex items-center gap-3">
<div className="p-2 rounded-lg bg-green-500/10 text-green-600">
<Shield className="h-5 w-5" />
</div>
<span className="text-muted-foreground">Enterprise-grade security</span>
<span className="text-muted-foreground">
Enterprise-grade security
</span>
</div>
<div className="flex items-center gap-3">
<div className="p-2 rounded-lg bg-blue-500/10 text-blue-600">
<Zap className="h-5 w-5" />
</div>
<span className="text-muted-foreground">AI-powered conversation analysis</span>
<span className="text-muted-foreground">
AI-powered conversation analysis
</span>
</div>
</div>
</div>
@ -130,13 +143,19 @@ export default function LoginPage() {
</CardDescription>
</CardHeader>
<CardContent>
{/* Live region for screen reader announcements */}
<div role="status" aria-live="polite" className="sr-only">
{isLoading && "Signing in, please wait..."}
{error && `Error: ${error}`}
</div>
{error && (
<Alert variant="destructive" className="mb-6">
<Alert variant="destructive" className="mb-6" role="alert">
<AlertDescription>{error}</AlertDescription>
</Alert>
)}
<form onSubmit={handleLogin} className="space-y-4">
<form onSubmit={handleLogin} className="space-y-4" noValidate>
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input
@ -147,8 +166,13 @@ export default function LoginPage() {
onChange={(e) => setEmail(e.target.value)}
disabled={isLoading}
required
aria-describedby="email-help"
aria-invalid={!!error}
className="transition-all duration-200 focus:ring-2 focus:ring-primary/20"
/>
<div id="email-help" className="sr-only">
Enter your company email address
</div>
</div>
<div className="space-y-2">
<Label htmlFor="password">Password</Label>
@ -160,39 +184,57 @@ export default function LoginPage() {
onChange={(e) => setPassword(e.target.value)}
disabled={isLoading}
required
aria-describedby="password-help"
aria-invalid={!!error}
className="transition-all duration-200 focus:ring-2 focus:ring-primary/20"
/>
<div id="password-help" className="sr-only">
Enter your account password
</div>
</div>
<Button
type="submit"
className="w-full mt-6 h-11 bg-linear-to-r from-primary to-primary/90 hover:from-primary/90 hover:to-primary/80 transition-all duration-200"
disabled={isLoading}
disabled={isLoading || !email || !password}
aria-describedby={isLoading ? "loading-status" : undefined}
>
{isLoading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
<Loader2
className="mr-2 h-4 w-4 animate-spin"
aria-hidden="true"
/>
Signing in...
</>
) : (
"Sign in"
)}
</Button>
{isLoading && (
<div
id="loading-status"
className="sr-only"
aria-live="polite"
>
Authentication in progress, please wait
</div>
)}
</form>
<div className="mt-6 space-y-4">
<div className="text-center">
<Link
href="/register"
className="text-sm text-primary hover:underline transition-colors"
className="text-sm text-primary hover:underline transition-colors focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 rounded-sm"
>
Don't have a company account? Register here
Don&apos;t have a company account? Register here
</Link>
</div>
<div className="text-center">
<Link
href="/forgot-password"
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
className="text-sm text-muted-foreground hover:text-foreground transition-colors focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 rounded-sm"
>
Forgot your password?
</Link>
@ -203,11 +245,17 @@ export default function LoginPage() {
<p className="mt-8 text-center text-xs text-muted-foreground">
By signing in, you agree to our{" "}
<Link href="/terms" className="text-primary hover:underline">
<Link
href="/terms"
className="text-primary hover:underline focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 rounded-sm"
>
Terms of Service
</Link>{" "}
and{" "}
<Link href="/privacy" className="text-primary hover:underline">
<Link
href="/privacy"
className="text-primary hover:underline focus:outline-none focus:ring-2 focus:ring-primary focus:ring-offset-2 rounded-sm"
>
Privacy Policy
</Link>
</p>