import { useState, useEffect } from 'react' import { useAuth } from '@/hooks' import { useNavigate } from 'react-router-dom' import { groupService, Group } from '@/services' /** * Helper function to convert hex color to RGB values */ function hexToRgb(hex: string): { r: number; g: number; b: number } | null { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex) return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16), } : null } /** * Helper function to determine if text should be light or dark based on background color */ function getContrastTextColor(hexColor: string): string { const rgb = hexToRgb(hexColor) if (!rgb) return '#000000' // Calculate luminance const luminance = (0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b) / 255 return luminance > 0.5 ? '#000000' : '#ffffff' } /** * Helper function to lighten a hex color for hover state */ function lightenColor(hex: string, percent: number): string { const rgb = hexToRgb(hex) if (!rgb) return hex const lighten = (value: number) => Math.min(255, Math.floor(value + (255 - value) * percent)) const r = lighten(rgb.r).toString(16).padStart(2, '0') const g = lighten(rgb.g).toString(16).padStart(2, '0') const b = lighten(rgb.b).toString(16).padStart(2, '0') return `#${r}${g}${b}` } /** * Helper function to darken a hex color for border */ function darkenColor(hex: string, percent: number): string { const rgb = hexToRgb(hex) if (!rgb) return hex const darken = (value: number) => Math.max(0, Math.floor(value * (1 - percent))) const r = darken(rgb.r).toString(16).padStart(2, '0') const g = darken(rgb.g).toString(16).padStart(2, '0') const b = darken(rgb.b).toString(16).padStart(2, '0') return `#${r}${g}${b}` } export default function DashboardPage() { const { user, logout } = useAuth() const navigate = useNavigate() const [groups, setGroups] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [hoveredGroup, setHoveredGroup] = useState(null) useEffect(() => { const fetchGroups = async () => { try { setLoading(true) const fetchedGroups = await groupService.getGroups() setGroups(fetchedGroups) setError(null) } catch (err) { console.error('Failed to fetch groups:', err) setError('Failed to load groups') } finally { setLoading(false) } } fetchGroups() }, []) const handleCategoryClick = (groupName: string) => { navigate(`/requirements?group=${encodeURIComponent(groupName)}`) } const handleMyRequirementsClick = () => { navigate('/requirements') } return (
{/* Header */}

Digital Twin Requirements Tool

{/* Top Bar */}
{/* Breadcrumb */}
Projects ยป PeTWIN
{/* Language Toggle */}
English
Portuguese
{/* Admin Panel Button */} {/* User Info */}
{user?.full_name || user?.preferred_username || 'User'}{' '} (admin)
{/* Main Content */}
{/* Left Sidebar */}
{/* Requirements Search */}

Requirements Search

Search for specific elements by name or symbol.

{/* Create a Requirement */}

Create a Requirement

Register a new Requirement.

{/* Last Viewed Requirement */}

Last Viewed Requirement:

No requirement accessed yet

View More
{/* My Requirements */}

My Requirements

View your requirements and their properties.

{/* Requirement Report */}

Requirement Report

Generate the current status of this projects requirements in PDF format

{/* Right Content - Quick Search Filters */}

Quick Search Filters

{/* Loading State */} {loading && (
Loading groups...
)} {/* Error State */} {error && (
{error}
)} {/* Groups Grid */} {!loading && !error && groups.length > 0 && (
{groups.map((group) => { const isHovered = hoveredGroup === group.id const bgColor = isHovered ? lightenColor(group.hex_color, 0.2) : group.hex_color const borderColor = darkenColor(group.hex_color, 0.2) const textColor = getContrastTextColor(group.hex_color) return (
handleCategoryClick(group.group_name)} onMouseEnter={() => setHoveredGroup(group.id)} onMouseLeave={() => setHoveredGroup(null)} className="flex flex-col items-center justify-center p-6 cursor-pointer transition-colors min-h-[120px] rounded-lg" style={{ backgroundColor: bgColor, borderWidth: '2px', borderStyle: 'solid', borderColor: borderColor, }} > {group.group_name}
) })}
)} {/* Empty State */} {!loading && !error && groups.length === 0 && (
No groups found
)}
) }