All files / src/components/auth/ReleaseNotesInfoBox ReleaseNotesInfoBox.tsx

100% Statements 30/30
100% Branches 15/15
100% Functions 4/4
100% Lines 30/30

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                        1x 15x 15x 15x 15x 15x 15x     15x   15x 7x 1x 1x     6x 6x 6x   5x   1x 1x     4x     4x 3x     4x   1x 1x 1x       6x                 15x 12x     3x                   1x                                                            
/**
 * ReleaseNotesInfoBox Component
 * Displays release notes from a static text file on login screen
 * Only visible in development and staging environments
 */
 
import React, { useState, useEffect } from 'react';
import { Alert, AlertTitle, Box, Collapse, IconButton } from '@mui/material';
import { Close as CloseIcon } from '@mui/icons-material';
import { useTranslation } from 'react-i18next';
import { useEnvironment } from '@/contexts/useEnvironment';
 
export const ReleaseNotesInfoBox: React.FC = () => {
  const { t } = useTranslation();
  const environment = useEnvironment();
  const [notes, setNotes] = useState<string>('');
  const [loading, setLoading] = useState<boolean>(true);
  const [error, setError] = useState<boolean>(false);
  const [dismissed, setDismissed] = useState<boolean>(false);
 
  // Only show in development and staging
  const shouldShow = environment === 'development' || environment === 'staging';
 
  useEffect(() => {
    if (!shouldShow) {
      setLoading(false);
      return;
    }
 
    const fetchReleaseNotes = async () => {
      try {
        const response = await fetch('/release-notes.txt');
 
        if (!response.ok) {
          // File doesn't exist or fetch failed - not an error, just no notes
          setLoading(false);
          return;
        }
 
        const text = await response.text();
 
        // Only set notes if there's actual content (not empty or whitespace)
        if (text.trim()) {
          setNotes(text.trim());
        }
 
        setLoading(false);
      } catch (err) {
        console.warn('[ReleaseNotesInfoBox] Failed to fetch release notes:', err);
        setError(true);
        setLoading(false);
      }
    };
 
    fetchReleaseNotes();
  }, [shouldShow]);
 
  // Don't render anything if:
  // - Not in dev/staging environment
  // - Still loading
  // - Error occurred
  // - No notes content
  // - User dismissed the box
  if (!shouldShow || loading || error || !notes || dismissed) {
    return null;
  }
 
  return (
    <Collapse in={!dismissed}>
      <Box sx={{ mb: 2 }}>
        <Alert
          severity="info"
          action={
            <IconButton
              aria-label={t('actions.close')}
              color="inherit"
              size="small"
              onClick={() => setDismissed(true)}
            >
              <CloseIcon fontSize="inherit" />
            </IconButton>
          }
          sx={{
            '& .MuiAlert-message': {
              width: '100%',
            },
          }}
        >
          <AlertTitle sx={{ fontWeight: 'bold' }}>{t('releaseNotes.title')}</AlertTitle>
          <Box
            component="pre"
            sx={{
              fontFamily: 'inherit',
              fontSize: 'inherit',
              whiteSpace: 'pre-wrap',
              wordBreak: 'break-word',
              margin: 0,
              marginTop: 1,
            }}
          >
            {notes}
          </Box>
        </Alert>
      </Box>
    </Collapse>
  );
};