// ======================================== // TeamListView Component // ======================================== // Team card grid with tabs, search, and actions import * as React from 'react'; import { useIntl } from 'react-intl'; import { RefreshCw, Search, Users, X, } from 'lucide-react'; import { Button } from '@/components/ui/Button'; import { Input } from '@/components/ui/Input'; import { TabsNavigation } from '@/components/ui/TabsNavigation'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, } from '@/components/ui/Dialog'; import { cn } from '@/lib/utils'; import { TeamCard, TeamCardSkeleton } from './TeamCard'; import { useTeamStore } from '@/stores/teamStore'; import { useTeams, useArchiveTeam, useUnarchiveTeam, useDeleteTeam } from '@/hooks/useTeamData'; export function TeamListView() { const { formatMessage } = useIntl(); const { locationFilter, setLocationFilter, searchQuery, setSearchQuery, selectTeamAndShowDetail, } = useTeamStore(); // Dialog state const [deleteDialogOpen, setDeleteDialogOpen] = React.useState(false); const [teamToDelete, setTeamToDelete] = React.useState(null); // Data const { teams, isLoading, isFetching, refetch } = useTeams(locationFilter); const { archiveTeam, isArchiving } = useArchiveTeam(); const { unarchiveTeam, isUnarchiving } = useUnarchiveTeam(); const { deleteTeam, isDeleting } = useDeleteTeam(); const isMutating = isArchiving || isUnarchiving || isDeleting; // Client-side search filter const filteredTeams = React.useMemo(() => { if (!searchQuery) return teams; const q = searchQuery.toLowerCase(); return teams.filter((t) => t.name.toLowerCase().includes(q)); }, [teams, searchQuery]); // Handlers const handleArchive = async (name: string) => { try { await archiveTeam(name); } catch (err) { console.error('Failed to archive team:', err); } }; const handleUnarchive = async (name: string) => { try { await unarchiveTeam(name); } catch (err) { console.error('Failed to unarchive team:', err); } }; const handleDeleteClick = (name: string) => { setTeamToDelete(name); setDeleteDialogOpen(true); }; const handleConfirmDelete = async () => { if (!teamToDelete) return; try { await deleteTeam(teamToDelete); setDeleteDialogOpen(false); setTeamToDelete(null); } catch (err) { console.error('Failed to delete team:', err); } }; const handleClearSearch = () => setSearchQuery(''); return (
{/* Header */}

{formatMessage({ id: 'team.title' })}

{formatMessage({ id: 'team.description' })}

{/* Filters */}
{/* Location tabs */} setLocationFilter(v as 'active' | 'archived' | 'all')} tabs={[ { value: 'active', label: formatMessage({ id: 'team.filters.active' }) }, { value: 'archived', label: formatMessage({ id: 'team.filters.archived' }) }, { value: 'all', label: formatMessage({ id: 'team.filters.all' }) }, ]} /> {/* Search input */}
setSearchQuery(e.target.value)} className="pl-9 pr-9" /> {searchQuery && ( )}
{/* Team grid */} {isLoading ? (
{Array.from({ length: 6 }).map((_, i) => ( ))}
) : filteredTeams.length === 0 ? (

{searchQuery ? formatMessage({ id: 'team.emptyState.noMatching' }) : formatMessage({ id: 'team.emptyState.noTeams' })}

{searchQuery ? formatMessage({ id: 'team.emptyState.noMatchingDescription' }) : formatMessage({ id: 'team.emptyState.noTeamsDescription' })}

{searchQuery && ( )}
) : (
{filteredTeams.map((team) => ( ))}
)} {/* Delete Confirmation Dialog */} {formatMessage({ id: 'team.dialog.deleteTeam' })} {formatMessage({ id: 'team.dialog.deleteConfirm' })}
); }