All files / src/components/organizer/EventPage/cockpit CockpitTab.tsx

100% Statements 8/8
66.66% Branches 4/6
100% Functions 1/1
100% Lines 8/8

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78                                                                1x 5x 5x 5x 5x 5x   5x   5x                                                                        
/**
 * CockpitTab (Epic 14 Phase B — Story 14.B.1; FR7).
 *
 * The task-driven Cockpit landing — three stacked regions:
 *   1. lifecycle spine ("where is this event")
 *   2. "Needs your attention" (sorted, only-open cards + +Add task)
 *   3. "At a glance" metric tiles (clickable deep-links)
 *
 * No event-identity block here — identity lives in Details; orientation is the
 * persistent header title + the spine (FR7). Replaces the interim Overview mount.
 */
 
import React from 'react';
import { Stack, Typography } from '@mui/material';
import { useTranslation } from 'react-i18next';
import type { Event, EventDetailUI } from '@/types/event.types';
import { useAuth } from '@/hooks/useAuth';
import { useBreakpoints } from '@/hooks/useBreakpoints';
import { WORKFLOW_RELEVANCE, type WorkflowStateType } from '@/utils/workflow/workflowState';
import { LifecycleSpine } from './LifecycleSpine';
import { AttentionList } from './AttentionList';
import { MetricTiles } from './MetricTiles';
import { useCockpitCards } from './useCockpitCards';
import type { CardTarget } from './cockpitCards';
 
interface CockpitTabProps {
  event: Event | EventDetailUI;
  eventCode: string;
  /** Deep-link handler from EventPage (tab/sub-view switch or route navigation). */
  onNavigate: (target: CardTarget) => void;
}
 
export const CockpitTab: React.FC<CockpitTabProps> = ({ event, eventCode, onNavigate }) => {
  const { t } = useTranslation('events');
  const { user } = useAuth();
  const { isMobile } = useBreakpoints();
  const workflowState = (event as { workflowState?: string }).workflowState ?? '';
  const { cards, isLoading, isError, refetch } = useCockpitCards(event, eventCode);
 
  const emphasis = WORKFLOW_RELEVANCE[workflowState as WorkflowStateType]?.cockpitEmphasis;
 
  return (
    <Stack spacing={4} data-testid="cockpit-tab">
      {/* Region 1 — lifecycle spine */}
      <div>
        {/* Mobile (Phase G — 14.G.2): the spine collapses to a "Step N/8" bar. */}
        <LifecycleSpine workflowState={workflowState} compact={isMobile} />
        {emphasis && (
          <Typography variant="body2" color="text.secondary" sx={{ mt: 1 }}>
            {t(`eventPage.cockpit.emphasis.${emphasis}`, '')}
          </Typography>
        )}
      </div>
 
      {/* Region 2 — needs your attention */}
      <AttentionList
        cards={cards}
        isLoading={isLoading}
        isError={isError}
        onRetry={refetch}
        onNavigate={onNavigate}
        eventCode={eventCode}
        organizerUsername={user?.username ?? ''}
      />
 
      {/* Region 3 — at a glance */}
      <div>
        <Typography variant="h6" gutterBottom>
          {t('eventPage.cockpit.atAGlance.title', 'At a glance')}
        </Typography>
        <MetricTiles event={event} onNavigate={onNavigate} />
      </div>
    </Stack>
  );
};
 
export default CockpitTab;