import { useState, useEffect, useCallback } from 'react'; import { Link, useNavigate } from 'react-router-dom'; import { TeamDetail, TeamCreate, PaginatedResponse } from '../types'; import { listTeams, createTeam } from '../api'; import { useAuth } from '../contexts/AuthContext'; import { Badge } from '../components/Badge'; import { DataTable } from '../components/DataTable'; import './TeamsPage.css'; function TeamsPage() { const navigate = useNavigate(); const { user } = useAuth(); const [teamsData, setTeamsData] = useState | null>(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [showForm, setShowForm] = useState(false); const [newTeam, setNewTeam] = useState({ name: '', slug: '', description: '' }); const [creating, setCreating] = useState(false); const [slugManuallySet, setSlugManuallySet] = useState(false); const [searchQuery, setSearchQuery] = useState(''); const loadTeams = useCallback(async () => { try { setLoading(true); const data = await listTeams({ limit: 100 }); setTeamsData(data); setError(null); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to load teams'); } finally { setLoading(false); } }, []); useEffect(() => { loadTeams(); }, [loadTeams]); // Auto-generate slug from name const handleNameChange = (name: string) => { setNewTeam(prev => ({ ...prev, name, slug: slugManuallySet ? prev.slug : name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, ''), })); }; const handleSlugChange = (slug: string) => { setSlugManuallySet(true); setNewTeam(prev => ({ ...prev, slug })); }; async function handleCreateTeam(e: React.FormEvent) { e.preventDefault(); try { setCreating(true); const team = await createTeam(newTeam); setNewTeam({ name: '', slug: '', description: '' }); setSlugManuallySet(false); setShowForm(false); navigate(`/teams/${team.slug}`); } catch (err) { setError(err instanceof Error ? err.message : 'Failed to create team'); } finally { setCreating(false); } } const closeModal = () => { setShowForm(false); setNewTeam({ name: '', slug: '', description: '' }); setSlugManuallySet(false); }; // Filter teams by search const filteredTeams = teamsData?.items.filter(team => team.name.toLowerCase().includes(searchQuery.toLowerCase()) || team.slug.toLowerCase().includes(searchQuery.toLowerCase()) || (team.description?.toLowerCase().includes(searchQuery.toLowerCase())) ) || []; const totalTeams = teamsData?.items.length || 0; const roleConfig: Record = { owner: { variant: 'success', label: 'Owner' }, admin: { variant: 'info', label: 'Admin' }, member: { variant: 'default', label: 'Member' }, }; if (!user) { return (

Sign in to view your teams

Teams help you organize projects and collaborate with others.

Sign In
); } return (
{/* Header */}

Teams

{/* Search */} {!loading && totalTeams > 3 && (
setSearchQuery(e.target.value)} className="teams-search__input" /> {searchQuery && ( )}
)} {error && (
{error}
)} {/* Create Team Modal */} {showForm && (
e.stopPropagation()}>

Create New Team

handleNameChange(e.target.value)} placeholder="Engineering" required autoFocus />
@ handleSlugChange(e.target.value)} placeholder="engineering" pattern="^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$" title="Lowercase letters, numbers, and hyphens only" required />
Used in URLs. Lowercase letters, numbers, and hyphens.