feat(m4): project & member management with tests and e2e

- ProjectRepository, ProjectMemberRepository, minimal NotificationRepository
- ProjectService: create/update/archive/delete project, add/remove member,
  permission checks (isMember/admin), member-added notification, getDashboard
  skeleton, getMyProjects, getMemberRole
- projectValidator, API services factory
- API routes: projects CRUD, members list/add/remove
- Screens: dashboard (project list + create form), project overview, members,
  settings; layout (Header/Sidebar/ProjectNav) and project components
- Unit tests (Project/ProjectMember repositories, ProjectService),
  integration project-member-permission, e2e project-management
This commit is contained in:
Ken Yasue
2026-06-25 01:02:10 +02:00
parent 8a67523c0e
commit 9eb391ea8d
30 changed files with 2230 additions and 14 deletions

View File

@ -0,0 +1,40 @@
import type { Project } from '@/lib/types';
const STATUS_LABELS: Record<string, string> = {
active: 'Active',
on_hold: 'On Hold',
completed: 'Completed',
archived: 'Archived',
};
const STATUS_COLORS: Record<string, string> = {
active: 'bg-green-100 text-green-800',
on_hold: 'bg-yellow-100 text-yellow-800',
completed: 'bg-blue-100 text-blue-800',
archived: 'bg-gray-200 text-gray-700',
};
export function ProjectCard({ project }: { project: Project }) {
return (
<a
href={`/projects/${project.id}`}
className="block rounded-lg border bg-white p-4 shadow-sm transition hover:shadow-md"
>
<div className="flex items-center justify-between">
<h3 className="font-semibold text-gray-800">{project.name}</h3>
<span
className={`rounded px-2 py-0.5 text-xs ${
STATUS_COLORS[project.status] ?? 'bg-gray-100 text-gray-700'
}`}
>
{STATUS_LABELS[project.status] ?? project.status}
</span>
</div>
{project.description && (
<p className="mt-2 line-clamp-2 text-sm text-gray-600">
{project.description}
</p>
)}
</a>
);
}