All files / src/components/help HelpPanel.tsx

98.07% Statements 153/156
100% Branches 9/9
75% Functions 3/4
98.07% Lines 153/156

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 149 150 151 152 153 154 155 156 1571x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 9x 9x 9x 9x 9x 9x 9x 9x 1x 1x 8x 8x 8x 9x 1x 1x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 7x 6x 6x 6x 6x 6x 6x 6x 6x       6x 6x 6x 6x 6x 6x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 1x 1x  
/**
 * @file HelpPanel.tsx
 * @description
 * Global help drawer component that displays help topics.
 * Renders as a right-side drawer and can be opened/closed from anywhere.
 *
 * @enterprise
 * - Right-side drawer (non-intrusive)
 * - Smooth transitions
 * - Responsive on mobile (full width)
 * - Close button and Escape key support
 *
 * @usage
 * Place at root of AppShell or layout:
 * <HelpPanel />
 */
import * as React from 'react';
import {
  Drawer,
  Box,
  Typography,
  IconButton,
  Button,
  Stack,
  Divider,
} from '@mui/material';
import CloseIcon from '@mui/icons-material/Close';
import OpenInNewIcon from '@mui/icons-material/OpenInNew';
import { useTranslation } from 'react-i18next';
import { useHelp } from '../../hooks/useHelp';
import { getHelpTopic } from '../../help/topics';
 
interface HelpPanelProps {
  /** Width of drawer on desktop */
  width?: number;
  /** Drawer position */
  position?: 'right' | 'left';
}
 
/**
 * HelpPanel: Global help drawer component
 * Displays help topic content retrieved from context
 */
const HelpPanel: React.FC<HelpPanelProps> = ({ width = 420, position = 'right' }) => {
  const { currentTopicId, isOpen, closeHelp } = useHelp();
  const { t } = useTranslation('help');
 
  // Allow runtime topic keys from registry while keeping `t` strongly typed
  const translate = (key: string): string => (t as unknown as (k: string) => string)(key);
 
  // If no topic selected or drawer is closed, don't render
  if (!currentTopicId || !isOpen) {
    return null;
  }
 
  // Get topic metadata
  const topic = getHelpTopic(currentTopicId);
  if (!topic) {
    return null;
  }
 
  return (
    <Drawer
      anchor={position}
      open={isOpen}
      onClose={closeHelp}
      sx={{
        zIndex: (theme) => theme.zIndex.modal + 10,
        '& .MuiDrawer-paper': {
          width: { xs: '100%', sm: width },
          maxHeight: '100vh',
          overflow: 'auto',
          boxShadow: 3,
        },
      }}
    >
      {/* Header with title and close button */}
      <Box
        sx={{
          display: 'flex',
          justifyContent: 'space-between',
          alignItems: 'center',
          p: 2,
          borderBottom: '1px solid',
          borderColor: 'divider',
          bgcolor: 'background.paper',
          position: 'sticky',
          top: 0,
          zIndex: 1,
        }}
      >
        <Typography variant="h6" sx={{ fontWeight: 700, flex: 1 }}>
          {translate(topic.titleKey)}
        </Typography>
        <IconButton onClick={closeHelp} size="small" sx={{ ml: 1 }}>
          <CloseIcon />
        </IconButton>
      </Box>
 
      {/* Content */}
      <Box sx={{ p: 3, display: 'flex', flexDirection: 'column', gap: 2 }}>
        {/* Help body text */}
        <Typography 
          variant="body2" 
          color="text.secondary" 
          sx={{ lineHeight: 1.7, whiteSpace: 'pre-line' }}
        >
          {translate(topic.bodyKey)}
        </Typography>
 
        {/* Optional: documentation link */}
        {topic.linkKey && (
          <>
            <Divider />
            <Stack direction="row" spacing={1}>
              <Button
                variant="outlined"
                size="small"
                endIcon={<OpenInNewIcon />}
                onClick={() => {
                  // Future: Open documentation URL
                  closeHelp();
                }}
                sx={{ textTransform: 'none' }}
              >
                {translate(topic.linkKey)}
              </Button>
            </Stack>
          </>
        )}
      </Box>
 
      {/* Footer spacer */}
      <Box sx={{ flex: 1 }} />
 
      {/* Footer hint */}
      <Box
        sx={{
          p: 2,
          borderTop: '1px solid',
          borderColor: 'divider',
          bgcolor: 'background.default',
          textAlign: 'center',
          position: 'sticky',
          bottom: 0,
        }}
      >
        <Typography variant="caption" color="text.secondary">
          {t('help:general.closeHint', 'Press Escape to close')}
        </Typography>
      </Box>
    </Drawer>
  );
};
 
export default HelpPanel;