feat: remove nginx, add projects/milestones/notifications pages
- Dockerfile: replace nginx with serve for static files - Fix auth endpoint: /auth/login → /auth/token - Add ProjectsPage, ProjectDetailPage - Add MilestonesPage, MilestoneDetailPage with progress bar - Add NotificationsPage with unread count - Sidebar: add milestones/notifications nav, live unread badge - API: configurable VITE_API_BASE for host nginx proxy - Types: add Milestone, MilestoneProgress, Notification, ProjectMember
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { Link, useLocation } from 'react-router-dom'
|
||||
import api from '@/services/api'
|
||||
import type { User } from '@/types'
|
||||
|
||||
interface Props {
|
||||
@@ -8,10 +10,26 @@ interface Props {
|
||||
|
||||
export default function Sidebar({ user, onLogout }: Props) {
|
||||
const { pathname } = useLocation()
|
||||
const [unreadCount, setUnreadCount] = useState(0)
|
||||
|
||||
useEffect(() => {
|
||||
api.get<{ count: number }>('/notifications/count')
|
||||
.then(({ data }) => setUnreadCount(data.count))
|
||||
.catch(() => {})
|
||||
const timer = setInterval(() => {
|
||||
api.get<{ count: number }>('/notifications/count')
|
||||
.then(({ data }) => setUnreadCount(data.count))
|
||||
.catch(() => {})
|
||||
}, 30000)
|
||||
return () => clearInterval(timer)
|
||||
}, [])
|
||||
|
||||
const links = [
|
||||
{ to: '/', icon: '📊', label: '仪表盘' },
|
||||
{ to: '/issues', icon: '📋', label: 'Issues' },
|
||||
{ to: '/projects', icon: '📁', label: '项目' },
|
||||
{ to: '/milestones', icon: '🏁', label: '里程碑' },
|
||||
{ to: '/notifications', icon: '🔔', label: `通知${unreadCount > 0 ? ` (${unreadCount})` : ''}` },
|
||||
]
|
||||
|
||||
return (
|
||||
@@ -21,7 +39,7 @@ export default function Sidebar({ user, onLogout }: Props) {
|
||||
</div>
|
||||
<ul className="nav-links">
|
||||
{links.map((l) => (
|
||||
<li key={l.to} className={pathname === l.to ? 'active' : ''}>
|
||||
<li key={l.to} className={pathname === l.to || (l.to !== '/' && pathname.startsWith(l.to)) ? 'active' : ''}>
|
||||
<Link to={l.to}>{l.icon} {l.label}</Link>
|
||||
</li>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user