feat: Update Layout and ApproveIdentified components with improved navigation and labeling
This commit enhances the Layout component by introducing a state for managing the visibility of maintenance navigation items and refactoring the navigation rendering logic for better clarity. The primary and maintenance navigation items have been separated for improved organization, and labels for navigation items have been updated for better user understanding. Additionally, the ApproveIdentified component has been updated to change the button label from "Report" to "Statistics," providing clearer context for the action. Documentation has been updated to reflect these changes.
This commit is contained in:
parent
a0cc3a985a
commit
638ed18033
@ -1,4 +1,4 @@
|
||||
import { useCallback } from 'react'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { Outlet, Link, useLocation } from 'react-router-dom'
|
||||
import { useAuth } from '../context/AuthContext'
|
||||
import { useInactivityTimeout } from '../hooks/useInactivityTimeout'
|
||||
@ -8,6 +8,7 @@ const INACTIVITY_TIMEOUT_MS = 30 * 60 * 1000
|
||||
export default function Layout() {
|
||||
const location = useLocation()
|
||||
const { username, logout, isAdmin, isAuthenticated } = useAuth()
|
||||
const [maintenanceExpanded, setMaintenanceExpanded] = useState(true)
|
||||
|
||||
const handleInactivityLogout = useCallback(() => {
|
||||
logout()
|
||||
@ -19,25 +20,54 @@ export default function Layout() {
|
||||
isEnabled: isAuthenticated,
|
||||
})
|
||||
|
||||
const allNavItems = [
|
||||
const primaryNavItems = [
|
||||
{ path: '/scan', label: 'Scan', icon: '🗂️', adminOnly: false },
|
||||
{ path: '/process', label: 'Process', icon: '⚙️', adminOnly: false },
|
||||
{ path: '/search', label: 'Search', icon: '🔍', adminOnly: false },
|
||||
{ path: '/identify', label: 'Identify', icon: '👤', adminOnly: false },
|
||||
{ path: '/search', label: 'Search Photos', icon: '🔍', adminOnly: false },
|
||||
{ path: '/identify', label: 'Identify People', icon: '👤', adminOnly: false },
|
||||
{ path: '/auto-match', label: 'Auto-Match', icon: '🤖', adminOnly: false },
|
||||
{ path: '/modify', label: 'Modify', icon: '✏️', adminOnly: false },
|
||||
{ path: '/tags', label: 'Tag', icon: '🏷️', adminOnly: false },
|
||||
{ path: '/faces-maintenance', label: 'Faces Maintenance', icon: '🔧', adminOnly: false },
|
||||
{ path: '/approve-identified', label: 'Approve identified', icon: '✅', adminOnly: true },
|
||||
{ path: '/manage-users', label: 'Manage users', icon: '👥', adminOnly: true },
|
||||
{ path: '/reported-photos', label: 'Reported photos', icon: '🚩', adminOnly: true },
|
||||
{ path: '/pending-photos', label: 'Manage User Uploaded Photos', icon: '📤', adminOnly: true },
|
||||
{ path: '/modify', label: 'Modify People', icon: '✏️', adminOnly: false },
|
||||
{ path: '/tags', label: 'Tag Photos', icon: '🏷️', adminOnly: false },
|
||||
]
|
||||
|
||||
const maintenanceNavItems = [
|
||||
{ path: '/faces-maintenance', label: 'Faces', icon: '🔧', adminOnly: false },
|
||||
{ path: '/approve-identified', label: 'User Identified Faces', icon: '✅', adminOnly: true },
|
||||
{ path: '/reported-photos', label: 'User Reported Photos', icon: '🚩', adminOnly: true },
|
||||
{ path: '/pending-photos', label: 'User Uploaded Photos', icon: '📤', adminOnly: true },
|
||||
{ path: '/manage-users', label: 'Users', icon: '👥', adminOnly: true },
|
||||
]
|
||||
|
||||
const footerNavItems = [
|
||||
{ path: '/settings', label: 'Settings', icon: '⚙️', adminOnly: false },
|
||||
{ path: '/help', label: 'Help', icon: '📚', adminOnly: false },
|
||||
]
|
||||
|
||||
// Filter nav items based on admin status
|
||||
const navItems = allNavItems.filter((item) => !item.adminOnly || isAdmin)
|
||||
const filterNavItems = (items: typeof primaryNavItems) =>
|
||||
items.filter((item) => !item.adminOnly || isAdmin)
|
||||
|
||||
const renderNavLink = (
|
||||
item: { path: string; label: string; icon: string },
|
||||
extraClasses = ''
|
||||
) => {
|
||||
const isActive = location.pathname === item.path
|
||||
return (
|
||||
<Link
|
||||
key={item.path}
|
||||
to={item.path}
|
||||
className={`flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transition-colors ${
|
||||
isActive ? 'bg-blue-50 text-blue-700' : 'text-gray-700 hover:bg-gray-50'
|
||||
} ${extraClasses}`}
|
||||
>
|
||||
<span>{item.icon}</span>
|
||||
<span>{item.label}</span>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
const visiblePrimary = filterNavItems(primaryNavItems)
|
||||
const visibleMaintenance = filterNavItems(maintenanceNavItems)
|
||||
const visibleFooter = filterNavItems(footerNavItems)
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50">
|
||||
@ -68,23 +98,31 @@ export default function Layout() {
|
||||
{/* Left sidebar - fixed position */}
|
||||
<div className="fixed left-0 top-16 w-64 bg-white border-r border-gray-200 h-[calc(100vh-4rem)] overflow-y-auto">
|
||||
<nav className="p-4 space-y-1">
|
||||
{navItems.map((item) => {
|
||||
const isActive = location.pathname === item.path
|
||||
return (
|
||||
<Link
|
||||
key={item.path}
|
||||
to={item.path}
|
||||
className={`flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transition-colors ${
|
||||
isActive
|
||||
? 'bg-blue-50 text-blue-700'
|
||||
: 'text-gray-700 hover:bg-gray-50'
|
||||
}`}
|
||||
{visiblePrimary.map((item) => renderNavLink(item))}
|
||||
|
||||
{isAdmin && visibleMaintenance.length > 0 && (
|
||||
<div className="mt-4">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setMaintenanceExpanded((prev) => !prev)}
|
||||
className="w-full px-3 py-2 text-xs font-semibold uppercase tracking-wide text-gray-500 flex items-center justify-between hover:text-gray-700"
|
||||
>
|
||||
<span>{item.icon}</span>
|
||||
<span>{item.label}</span>
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
<span>Maintenance</span>
|
||||
<span>{maintenanceExpanded ? '▼' : '▶'}</span>
|
||||
</button>
|
||||
{maintenanceExpanded && (
|
||||
<div className="mt-1 space-y-1">
|
||||
{visibleMaintenance.map((item) => renderNavLink(item, 'ml-4'))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{visibleFooter.length > 0 && (
|
||||
<div className="mt-4 space-y-1">
|
||||
{visibleFooter.map((item) => renderNavLink(item))}
|
||||
</div>
|
||||
)}
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
|
||||
@ -237,7 +237,7 @@ export default function ApproveIdentified() {
|
||||
onClick={handleOpenReport}
|
||||
className="px-3 py-1.5 text-sm bg-green-100 text-green-700 rounded-md hover:bg-green-200 font-medium"
|
||||
>
|
||||
📊 Report
|
||||
📊 Statistics
|
||||
</button>
|
||||
<button
|
||||
onClick={handleClearDenied}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user