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

89 lines
3.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { redirect } from 'next/navigation';
import { getCurrentUser, toPublicUser } from '@/lib/auth/getCurrentUser';
import { createDashboardService } from '@/lib/api/services';
import { Header } from '@/components/layout/Header';
import { CreateProjectForm } from '@/components/project/CreateProjectForm';
import { DashboardWidget } from '@/components/project/DashboardWidget';
export const dynamic = 'force-dynamic';
export default async function DashboardPage() {
const user = await getCurrentUser();
if (!user) {
redirect('/login');
}
const service = createDashboardService();
const dashboard = service.getPersonalDashboard(user.id);
return (
<div className="min-h-screen bg-gray-50">
<Header user={toPublicUser(user)} />
<main className="mx-auto max-w-4xl space-y-6 p-6">
<h1 className="text-2xl font-bold"></h1>
<div className="grid gap-4 sm:grid-cols-2">
<DashboardWidget title="参加プロジェクト" empty="ありません">
{dashboard.projects.map((p) => (
<a
key={p.id}
href={`/projects/${p.id}`}
className="block rounded border px-3 py-2 text-sm hover:bg-gray-50"
>
{p.name}{p.status}
</a>
))}
</DashboardWidget>
<DashboardWidget
title={`未読通知 (${dashboard.unreadNotificationCount})`}
empty="未読はありません"
>
<a
href="/notifications"
className="text-sm text-blue-600 hover:underline"
>
</a>
</DashboardWidget>
<DashboardWidget title="未完了ToDo" empty="ありません">
{dashboard.incompleteTodos.map((t) => (
<p key={t.id} className="text-sm">
{t.title}
{t.dueDate ? `(期限: ${t.dueDate}` : ''}
</p>
))}
</DashboardWidget>
<DashboardWidget title="期限切れタスク" empty="ありません">
{dashboard.overdueTasks.map((t) => (
<p key={t.id} className="text-sm text-red-600">
{t.title}: {t.dueDate}
</p>
))}
</DashboardWidget>
<DashboardWidget title="近日中のミーティング" empty="ありません">
{dashboard.upcomingMeetings.map((m) => (
<p key={m.id} className="text-sm">
{m.title}{m.startAt}
</p>
))}
</DashboardWidget>
<DashboardWidget title="最近のアクティビティ" empty="ありません">
{dashboard.recentActivity.map((l) => (
<p key={l.id} className="text-sm">
{l.action}{l.targetType}
</p>
))}
</DashboardWidget>
</div>
<CreateProjectForm />
</main>
</div>
);
}