All files / src/components/organizer/EventManagement WorkflowProgressBar.tsx

100% Statements 13/13
78.26% Branches 18/23
100% Functions 3/3
100% Lines 12/12

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 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148                                                                                2x       13x 13x 13x     13x               13x 13x     13x     13x       13x   6x                       13x                                                                                                                                  
/**
 * WorkflowProgressBar Component
 *
 * Story 2.5.3 - Task 10b (GREEN Phase)
 * AC: 5 (Workflow Progress Display)
 * Wireframe: docs/wireframes/story-1.16-workflow-visualization.md
 *
 * Displays workflow progress with:
 * - Progress bar showing completion percentage (0-100%)
 * - Current step indicator (Step X/8: Step Name)
 * - Clickable progress bar navigation to workflow visualization
 * - Warning indicators for blockers (⚠️)
 * - [View Workflow Details] button
 * - Color-coded progress (warning <30%, primary 30-70%, success >70%)
 * - Full accessibility (keyboard navigation, ARIA labels)
 */
 
import React from 'react';
import {
  Box,
  LinearProgress,
  Typography,
  Tooltip,
  Stack,
  Chip,
  useTheme,
  useMediaQuery,
} from '@mui/material';
import { Warning as WarningIcon, Error as ErrorIcon } from '@mui/icons-material';
import { useTranslation } from 'react-i18next';
import type { WorkflowState } from '@/types/event.types';
import { WORKFLOW_STATE_ORDER, getProgressColor } from '@/utils/workflow/workflowState';
 
interface WorkflowProgressBarProps {
  workflow: WorkflowState;
  compact?: boolean;
  /** Optional: Explicit workflow state (overrides derivation from currentStep) */
  workflowState?: string;
}
 
export const WorkflowProgressBar: React.FC<WorkflowProgressBarProps> = ({
  workflow,
  compact = false,
}) => {
  const { t } = useTranslation('events');
  const theme = useTheme();
  const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
 
  // Handle undefined/null workflow
  const safeWorkflow: WorkflowState = workflow || {
    currentStep: 1,
    totalSteps: WORKFLOW_STATE_ORDER.length,
    completionPercentage: 0,
    steps: [],
    blockers: [],
  };
 
  const { blockers } = safeWorkflow;
  const completionPercentage = Math.round(safeWorkflow.completionPercentage * 10) / 10;
 
  // Check for critical blockers
  const hasCriticalBlockers = blockers.some((b) => b.severity === 'critical');
 
  // Get progress bar color
  const progressColor = getProgressColor(completionPercentage);
 
  // Build blocker tooltip content
  const blockerTooltipContent = (
    <Stack spacing={1}>
      {blockers.map((blocker, index) => (
        <Box key={index}>
          <Typography variant="caption" fontWeight="bold">
            {blocker.severity === 'critical' ? '🔴' : '⚠️'} Step {blocker.stepNumber}
          </Typography>
          <Typography variant="caption" display="block">
            {blocker.message}
          </Typography>
        </Box>
      ))}
    </Stack>
  );
 
  return (
    <Box
      sx={{
        width: '100%',
        display: 'flex',
        flexDirection: compact || isMobile ? 'column' : 'row',
        alignItems: compact || isMobile ? 'stretch' : 'center',
        gap: 2,
      }}
      className={isMobile ? 'mobile stacked' : ''}
    >
      {/* Progress Bar Section */}
      <Box sx={{ flex: 1 }}>
        {/* Blocker Warning Indicator */}
        {blockers.length > 0 && (
          <Box mb={0.5}>
            <Tooltip title={blockerTooltipContent} arrow>
              <Chip
                icon={hasCriticalBlockers ? <ErrorIcon /> : <WarningIcon />}
                label={
                  <>
                    {hasCriticalBlockers && '🔴 '}⚠️{' '}
                    {t('workflow.blockers', { count: blockers.length })}
                  </>
                }
                size="small"
                color={hasCriticalBlockers ? 'error' : 'warning'}
                variant="outlined"
              />
            </Tooltip>
          </Box>
        )}
 
        {/* Progress Bar with Percentage */}
        <Stack direction="row" alignItems="center" spacing={1}>
          <Box
            role="progressbar"
            aria-valuenow={completionPercentage}
            aria-valuemin={0}
            aria-valuemax={100}
            aria-label={t('workflow.progressBarLabel', {
              percentage: completionPercentage,
            })}
            sx={{ flex: 1, borderRadius: 1, overflow: 'hidden' }}
          >
            <LinearProgress
              variant="determinate"
              value={completionPercentage}
              color={progressColor}
              sx={{
                height: 8,
                borderRadius: 1,
              }}
            />
          </Box>
          <Typography variant="body2" fontWeight="bold" sx={{ minWidth: '40px' }}>
            {completionPercentage}%
          </Typography>
        </Stack>
      </Box>
    </Box>
  );
};
 
export default WorkflowProgressBar;