Files
Ken Yasue 755c242d2b feat(m13): cross-resource search + dashboard completion, tests, e2e
- SearchService (cross-resource keyword search across board/chat/todo/file/
  event/meeting/milestone/note with type filter, project isolation)
- DashboardService (project dashboard: in-progress todos, near-due(7d),
  latest chat/board/notes/files(5), next meeting, milestones w/ progress,
  recent activity(10); personal dashboard: my projects, incomplete todos,
  upcoming meetings, unread notifications, overdue tasks, recent activity)
- CalendarRepository.findByProject
- APIs: GET /api/projects/:projectId/search, GET /api/dashboard
- Screens: complete personal dashboard, complete project overview,
  search page + SearchForm, ProjectNav 検索 link
- Unit tests (SearchService, DashboardService) + e2e dashboard
2026-06-25 02:28:17 +02:00

79 lines
2.1 KiB
TypeScript

const NAV_ITEMS = [
{ href: '', label: '概要' },
{ href: '/board', label: '掲示板' },
{ href: '/notes', label: 'メモ' },
{ href: '/chat', label: 'チャット' },
{ href: '/todos', label: 'ToDo' },
{ href: '/files', label: 'ファイル' },
{ href: '/calendar', label: 'カレンダー' },
{ href: '/milestones', label: 'マイルストーン' },
{ href: '/meetings', label: 'ミーティング' },
{ href: '/search', label: '検索' },
{ href: '/members', label: 'メンバー' },
{ href: '/activity', label: 'アクティビティ' },
{ href: '/settings', label: '設定' },
] as const;
/**
* プロジェクト内サブナビゲーション。
* href は `/projects/{projectId}` を起点とする相対パス。
*/
export function ProjectNav({
projectId,
active,
}: {
projectId: number;
active:
| 'overview'
| 'board'
| 'notes'
| 'chat'
| 'todos'
| 'files'
| 'calendar'
| 'milestones'
| 'meetings'
| 'search'
| 'members'
| 'activity'
| 'settings';
}) {
const activeMap: Record<string, boolean> = {
overview: active === 'overview',
board: active === 'board',
notes: active === 'notes',
chat: active === 'chat',
todos: active === 'todos',
files: active === 'files',
calendar: active === 'calendar',
milestones: active === 'milestones',
meetings: active === 'meetings',
search: active === 'search',
members: active === 'members',
activity: active === 'activity',
settings: active === 'settings',
};
return (
<nav className="flex gap-4 border-b bg-white px-6 py-2 text-sm">
{NAV_ITEMS.map((item) => {
const key = item.href === '' ? 'overview' : item.href.slice(1);
const href = `/projects/${projectId}${item.href}`;
return (
<a
key={item.href}
href={href}
className={
activeMap[key]
? 'font-medium text-blue-600'
: 'text-gray-600 hover:underline'
}
>
{item.label}
</a>
);
})}
</nav>
);
}