Normalized header layout after dashboard revision
This commit is contained in:
@@ -45,5 +45,6 @@
|
||||
"projects": "Projects",
|
||||
"project": "Project",
|
||||
"selectLanguage": "Select language",
|
||||
"logout": "Logout"
|
||||
"logout": "Logout",
|
||||
"admin": "Admin"
|
||||
}
|
||||
|
||||
@@ -45,5 +45,6 @@
|
||||
"projects": "Projetos",
|
||||
"project": "Projeto",
|
||||
"selectLanguage": "Selecionar idioma",
|
||||
"logout": "Sair"
|
||||
"logout": "Sair",
|
||||
"admin": "Admin"
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useAuth, useProject } from '@/hooks'
|
||||
import { useParams, Link } from 'react-router-dom'
|
||||
import { useParams, Link, useNavigate } from 'react-router-dom'
|
||||
import { requirementService, validationService, relationshipService, commentService, tagService, priorityService, groupService, requirementStatusService } from '@/services'
|
||||
import { LanguageSelector } from '@/components'
|
||||
import type { Requirement } from '@/services/requirementService'
|
||||
import type { RelationshipType, RequirementLink, RequirementSearchResult } from '@/services/relationshipService'
|
||||
import type { Tag } from '@/services/tagService'
|
||||
@@ -46,6 +47,7 @@ export default function RequirementDetailPage() {
|
||||
const { user, logout, isAuditor } = useAuth()
|
||||
const { currentProject } = useProject()
|
||||
const { id } = useParams<{ id: string }>()
|
||||
const navigate = useNavigate()
|
||||
const [activeTab, setActiveTab] = useState<TabType>('description')
|
||||
const [requirement, setRequirement] = useState<Requirement | null>(null)
|
||||
const [loading, setLoading] = useState(true)
|
||||
@@ -1650,46 +1652,82 @@ export default function RequirementDetailPage() {
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-white">
|
||||
{/* Header */}
|
||||
<header className="py-6 text-center">
|
||||
<h1 className="text-3xl font-semibold text-teal-700">
|
||||
{t('pageTitle')}
|
||||
</h1>
|
||||
</header>
|
||||
|
||||
{/* Top Bar */}
|
||||
<div className="border-y border-gray-200 py-3 px-8">
|
||||
<header className="bg-white border-b border-gray-200 px-8 py-4">
|
||||
<div className="flex items-center justify-between max-w-7xl mx-auto">
|
||||
{/* Breadcrumb */}
|
||||
<div className="text-sm">
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
<Link to="/dashboard" className="text-gray-600 hover:underline">{tCommon('projects')}</Link>
|
||||
<span className="mx-2 text-gray-400">»</span>
|
||||
<svg className="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
<Link to="/dashboard" className="text-gray-600 hover:underline">{currentProject?.project_name || tCommon('project')}</Link>
|
||||
<span className="mx-2 text-gray-400">»</span>
|
||||
<svg className="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
<Link to="/requirements" className="text-gray-600 hover:underline">{t('breadcrumb.search')}</Link>
|
||||
<span className="mx-2 text-gray-400">»</span>
|
||||
<svg className="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
<span className="font-semibold text-gray-900">{t('breadcrumb.details')} {tagCode}</span>
|
||||
</div>
|
||||
|
||||
{/* User Info */}
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<svg className="w-5 h-5 text-gray-600" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fillRule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clipRule="evenodd" />
|
||||
</svg>
|
||||
<span className="text-sm text-gray-700">
|
||||
{user?.full_name || user?.preferred_username || tCommon('user')}{' '}
|
||||
<span className="text-gray-500">({user?.role || tCommon('user')})</span>
|
||||
</span>
|
||||
{/* Right side utilities */}
|
||||
<div className="flex items-center gap-4">
|
||||
{/* Language Selector */}
|
||||
<LanguageSelector compact />
|
||||
|
||||
{/* Divider */}
|
||||
<div className="h-6 w-px bg-gray-300"></div>
|
||||
|
||||
{/* Admin Panel Button - Only visible for admins (role_id=3) */}
|
||||
{user?.role_id === 3 && (
|
||||
<button
|
||||
onClick={() => navigate('/admin')}
|
||||
className="flex items-center gap-2 px-3 py-1.5 text-sm font-medium text-gray-600 hover:text-gray-900 hover:bg-gray-100 rounded-lg transition-colors"
|
||||
>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>
|
||||
{tCommon('admin')}
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* User Info */}
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-8 h-8 bg-teal-100 rounded-full flex items-center justify-center">
|
||||
<svg className="w-4 h-4 text-teal-600" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fillRule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clipRule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<div className="text-sm">
|
||||
<p className="font-medium text-gray-700">
|
||||
{user?.full_name || user?.preferred_username || tCommon('user')}
|
||||
</p>
|
||||
<p className="text-xs text-gray-500">{user?.role || tCommon('user').toLowerCase()}</p>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={logout}
|
||||
className="p-2 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-lg transition-colors"
|
||||
title={tCommon('logout')}
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
onClick={logout}
|
||||
className="px-3 py-1 border border-gray-400 rounded text-sm text-gray-700 hover:bg-gray-50"
|
||||
>
|
||||
{tCommon('logout')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Page Title */}
|
||||
<div className="py-6 text-center border-b border-gray-100">
|
||||
<h1 className="text-3xl font-semibold text-teal-700">
|
||||
{t('pageTitle')}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
{/* Main Content */}
|
||||
|
||||
@@ -414,47 +414,78 @@ export default function RequirementsPage() {
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-white">
|
||||
{/* Header */}
|
||||
<header className="py-6 text-center">
|
||||
<h1 className="text-3xl font-semibold text-teal-700">
|
||||
{t('header.title')}
|
||||
</h1>
|
||||
</header>
|
||||
|
||||
{/* Top Bar */}
|
||||
<div className="border-y border-gray-200 py-3 px-8">
|
||||
<header className="bg-white border-b border-gray-200 px-8 py-4">
|
||||
<div className="flex items-center justify-between max-w-7xl mx-auto">
|
||||
{/* Breadcrumb */}
|
||||
<div className="text-sm">
|
||||
<div className="flex items-center gap-2 text-sm">
|
||||
<Link to="/dashboard" className="text-gray-600 hover:underline">{t('breadcrumb.projects')}</Link>
|
||||
<span className="mx-2 text-gray-400">»</span>
|
||||
<svg className="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
<Link to="/dashboard" className="text-gray-600 hover:underline">{currentProject.project_name}</Link>
|
||||
<span className="mx-2 text-gray-400">»</span>
|
||||
<svg className="w-4 h-4 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
<span className="font-semibold text-gray-900">{t('breadcrumb.searchRequirements')}</span>
|
||||
</div>
|
||||
|
||||
{/* Language Selector */}
|
||||
<LanguageSelector compact />
|
||||
{/* Right side utilities */}
|
||||
<div className="flex items-center gap-4">
|
||||
{/* Language Selector */}
|
||||
<LanguageSelector compact />
|
||||
|
||||
{/* User Info */}
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<svg className="w-5 h-5 text-gray-600" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fillRule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clipRule="evenodd" />
|
||||
</svg>
|
||||
<span className="text-sm text-gray-700">
|
||||
{user?.full_name || user?.preferred_username || tCommon('user')}{' '}
|
||||
<span className="text-gray-500">({user?.role || tCommon('user').toLowerCase()})</span>
|
||||
</span>
|
||||
{/* Divider */}
|
||||
<div className="h-6 w-px bg-gray-300"></div>
|
||||
|
||||
{/* Admin Panel Button - Only visible for admins (role_id=3) */}
|
||||
{user?.role_id === 3 && (
|
||||
<button
|
||||
onClick={() => navigate('/admin')}
|
||||
className="flex items-center gap-2 px-3 py-1.5 text-sm font-medium text-gray-600 hover:text-gray-900 hover:bg-gray-100 rounded-lg transition-colors"
|
||||
>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>
|
||||
{tCommon('admin')}
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* User Info */}
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-8 h-8 bg-teal-100 rounded-full flex items-center justify-center">
|
||||
<svg className="w-4 h-4 text-teal-600" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fillRule="evenodd" d="M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z" clipRule="evenodd" />
|
||||
</svg>
|
||||
</div>
|
||||
<div className="text-sm">
|
||||
<p className="font-medium text-gray-700">
|
||||
{user?.full_name || user?.preferred_username || tCommon('user')}
|
||||
</p>
|
||||
<p className="text-xs text-gray-500">{user?.role || tCommon('user').toLowerCase()}</p>
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={logout}
|
||||
className="p-2 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-lg transition-colors"
|
||||
title={tCommon('logout')}
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
onClick={logout}
|
||||
className="px-3 py-1 border border-gray-400 rounded text-sm text-gray-700 hover:bg-gray-50"
|
||||
>
|
||||
{tCommon('logout')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Page Title */}
|
||||
<div className="py-6 text-center border-b border-gray-100">
|
||||
<h1 className="text-3xl font-semibold text-teal-700">
|
||||
{t('header.title')}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
{/* Main Content */}
|
||||
|
||||
Reference in New Issue
Block a user