feat: introduce Teams & OKRs feature with models, types, and UI components for team management and objective tracking
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 12m53s
All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 12m53s
This commit is contained in:
85
src/app/teams/[id]/page.tsx
Normal file
85
src/app/teams/[id]/page.tsx
Normal file
@@ -0,0 +1,85 @@
|
||||
import { auth } from '@/lib/auth';
|
||||
import { redirect } from 'next/navigation';
|
||||
import Link from 'next/link';
|
||||
import { getTeam, isTeamAdmin } from '@/services/teams';
|
||||
import { getTeamOKRs } from '@/services/okrs';
|
||||
import { TeamDetailClient } from '@/components/teams/TeamDetailClient';
|
||||
import { DeleteTeamButton } from '@/components/teams/DeleteTeamButton';
|
||||
import { OKRsList } from '@/components/okrs';
|
||||
import { Button } from '@/components/ui';
|
||||
import { Card } from '@/components/ui';
|
||||
import { notFound } from 'next/navigation';
|
||||
import type { TeamMember } from '@/lib/types';
|
||||
|
||||
interface TeamDetailPageProps {
|
||||
params: Promise<{ id: string }>;
|
||||
}
|
||||
|
||||
export default async function TeamDetailPage({ params }: TeamDetailPageProps) {
|
||||
const { id } = await params;
|
||||
const session = await auth();
|
||||
|
||||
if (!session?.user?.id) {
|
||||
redirect('/login');
|
||||
}
|
||||
|
||||
const team = await getTeam(id);
|
||||
|
||||
if (!team) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
// Check if user is a member
|
||||
const isMember = team.members.some((m) => m.userId === session.user?.id);
|
||||
if (!isMember) {
|
||||
redirect('/teams');
|
||||
}
|
||||
|
||||
const isAdmin = await isTeamAdmin(id, session.user.id);
|
||||
const okrsData = await getTeamOKRs(id);
|
||||
|
||||
return (
|
||||
<main className="mx-auto max-w-7xl px-4 py-8">
|
||||
{/* Header */}
|
||||
<div className="mb-8">
|
||||
<div className="mb-4 flex items-center gap-2">
|
||||
<Link href="/teams" className="text-muted hover:text-foreground">
|
||||
← Retour aux équipes
|
||||
</Link>
|
||||
</div>
|
||||
<div className="flex items-start justify-between">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold text-foreground flex items-center gap-2">
|
||||
<span className="text-3xl">👥</span>
|
||||
{team.name}
|
||||
</h1>
|
||||
{team.description && <p className="mt-2 text-muted">{team.description}</p>}
|
||||
</div>
|
||||
{isAdmin && (
|
||||
<div className="flex items-center gap-3">
|
||||
<Link href={`/teams/${id}/okrs/new`}>
|
||||
<Button className="bg-[var(--purple)] text-white hover:opacity-90 border-transparent">
|
||||
Définir un OKR
|
||||
</Button>
|
||||
</Link>
|
||||
<DeleteTeamButton teamId={id} teamName={team.name} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Members Section */}
|
||||
<Card className="mb-8 p-6">
|
||||
<TeamDetailClient
|
||||
members={team.members as unknown as TeamMember[]}
|
||||
teamId={id}
|
||||
isAdmin={isAdmin}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
{/* OKRs Section */}
|
||||
<OKRsList okrsData={okrsData} teamId={id} />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user