Please update the generation animation. Currently, the entire summary appears all at once, but I'd like it to display an animation that reveals the text word by word.

code:

import React, { useState, useEffect, useContext } from 'react';
import { useParams } from 'react-router-dom';
import axios from 'axios';
import {
  Typography,
  Paper,
  Grid,
  CircularProgress, // For loading indicator
} from '@mui/material';
import { styled } from '@mui/system';
import { PieChart, Pie, Cell, ResponsiveContainer } from 'recharts';
import { AuthContext } from '../AuthContext'; // Import AuthContext for authentication
import { signOut } from 'firebase/auth';
import { auth } from '../firebase'; // Import your Firebase auth instance

// Optional: Import an icon for the diagram placeholder (e.g., InsertChartIcon)
import InsertChartIcon from '@mui/icons-material/InsertChart';

const Container = styled(Paper)(({ theme }) => ({
  padding: theme.spacing(4),
  margin: theme.spacing(4),
}));

function UserPage() {
  const { id } = useParams(); // Get the user ID from the route parameters
  const [userData, setUserData] = useState(null);
  const { currentUser } = useContext(AuthContext); // Access currentUser from context
  const [error, setError] = useState(null); // Error state
  const [isLoading, setIsLoading] = useState(true); // Loading state
  const [generatingSummary, setGeneratingSummary] = useState(false); // State for AI summary generation
  const [displayedSummary, setDisplayedSummary] = useState(''); // State for typing animation
  const [typing, setTyping] = useState(false); // Typing animation state

  useEffect(() => {
    // Function to fetch user data
    const fetchUserData = async () => {
      if (!currentUser) {
        setError('User is not authenticated.');
        setIsLoading(false);
        return;
      }

      try {
        const token = await currentUser.getIdToken(true); // Force token refresh
        const response = await axios.get(
          `https://us-central1-mind-gardener.cloudfunctions.net/api/users/${id}`,
          {
            headers: {
              Authorization: `Bearer ${token}`,
            },
          }
        );
        setUserData(response.data);
      } catch (err) {
        if (err.response) {
          if (err.response.status === 403) {
            setError('Access denied. You do not have permission to view this user.');
          } else if (err.response.status === 401) {
            setError('Unauthorized. Please log in again.');
          } else if (err.response.status === 404) {
            setError('User not found.');
          } else {
            setError('An error occurred while fetching user data.');
          }
        } else {
          setError('Failed to fetch user data.');
        }
      } finally {
        setIsLoading(false);
      }
    };

    fetchUserData();
  }, [id, currentUser]);

  useEffect(() => {
    // Automatically generate summary when userData is available and summary is not present
    const generateSummary = async () => {
      if (!userData || userData.summary) return; // Avoid regenerating if summary already exists or userData not loaded

      setGeneratingSummary(true);
      setError(null);
      setTyping(true);
      setDisplayedSummary(''); // Reset displayed summary

      try {
        const token = await currentUser.getIdToken(true); // Get fresh token
        const response = await axios.post(
          `https://us-central1-mind-gardener.cloudfunctions.net/api/generate-summary`,
          { userId: id },
          {
            headers: {
              Authorization: `Bearer ${token}`,
            },
          }
        );
        setUserData((prevState) => ({
          ...prevState,
          summary: response.data.summary, // Update the summary field
        }));
      } catch (err) {
        console.error('Error generating summary:', err);
        if (err.response && err.response.data && err.response.data.error) {
          setError(err.response.data.error);
        } else {
          setError('Error generating AI summary.');
        }
      } finally {
        setGeneratingSummary(false);
      }
    };

    generateSummary();
  }, [userData, currentUser, id]);

  useEffect(() => {
    // Typing animation for the summary
    if (userData && userData.summary && typing) {
      const summary = userData.summary;
      let index = 0;
      const typingSpeed = 50; // Milliseconds per character

      const typeInterval = setInterval(() => {
        setDisplayedSummary((prev) => prev + summary.charAt(index));
        index++;
        if (index > summary.length) {
          clearInterval(typeInterval);
          setTyping(false);
        }
      }, typingSpeed);

      return () => clearInterval(typeInterval);
    }
  }, [userData, typing]);

  const handleLogout = () => {
    signOut(auth)
      .then(() => {
        console.log('User signed out successfully.');
      })
      .catch((err) => {
        console.error('Error during sign out:', err);
      });
  };

  if (isLoading) {
    return (
      <Typography variant="h6" align="center" sx={{ mt: 4 }}>
        <CircularProgress />
      </Typography>
    );
  }

  if (error) {
    return (
      <Typography variant="h6" align="center" color="error" sx={{ mt: 4 }}>
        {error}
      </Typography>
    );
  }

  if (!userData) {
    return (
      <Typography variant="h6" align="center" sx={{ mt: 4 }}>
        No user data available.
      </Typography>
    );
  }

  const data = [
    { name: 'Positive', value: userData.sentimentScore },
    { name: 'Negative', value: 100 - userData.sentimentScore },
  ];

  const COLORS = ['#0088FE', '#FF8042'];

  return (
    <Container elevation={3}>
      <Grid container justifyContent="space-between" alignItems="center">
        <Typography variant="h4">User ID: {userData.id}</Typography>
        <Typography
          variant="button"
          onClick={handleLogout}
          sx={{ cursor: 'pointer', color: 'primary.main' }}
        >
          Logout
        </Typography>
      </Grid>

      <Typography variant="h6" gutterBottom sx={{ mt: 2 }}>
        Detailed User Information
      </Typography>

      <Grid container spacing={4}>
        <Grid item xs={12} md={8}>
          <Typography variant="subtitle1" gutterBottom>
            AI-Generated Summary:
          </Typography>

          {/* Display generated summary with typing animation and justified text */}
          {generatingSummary && (
            <Typography
              variant="body1"
              sx={{ mt: 2, textAlign: 'justify', whiteSpace: 'pre-wrap' }}
            >
              {/* Display the typing summary with blinking cursor */}
              {displayedSummary}
              <span className="cursor">|</span>
            </Typography>
          )}

          {!generatingSummary && userData.summary ? (
            <Typography variant="body1" sx={{ mt: 2, textAlign: 'justify' }}>
              {userData.summary}
            </Typography>
          ) : !generatingSummary && !userData.summary ? (
            <Typography variant="body1" sx={{ mt: 2, textAlign: 'justify' }}>
              Summary will be generated automatically.
            </Typography>
          ) : null}

          {/* Placeholder for Diagram/Chart */}
          <Typography variant="subtitle1" gutterBottom mt={4}>
            User Diagram:
          </Typography>
          <div
            style={{
              height: 300,
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              border: '2px dashed #ccc',
              borderRadius: '8px',
              backgroundColor: '#f9f9f9',
            }}
          >
            <InsertChartIcon color="action" sx={{ fontSize: 50, mr: 2 }} />
            <Typography variant="body2" color="textSecondary">
              Diagram or chart will be displayed here.
            </Typography>
          </div>
        </Grid>
        <Grid item xs={12} md={4}>
          <ResponsiveContainer width="100%" height={200}>
            <PieChart>
              <Pie
                data={data}
                dataKey="value"
                innerRadius={60}
                outerRadius={80}
                fill="#8884d8"
                paddingAngle={5}
                startAngle={90}
                endAngle={-270}
              >
                {data.map((entry, index) => (
                  <Cell key={`cell-${index}`} fill={COLORS[index % COLORS.length]} />
                ))}
              </Pie>
            </PieChart>
          </ResponsiveContainer>
          <Typography variant="body1" align="center">
            Sentiment Score: {userData.sentimentScore}%
          </Typography>
        </Grid>
      </Grid>

      {/* Optional: Add some global styling for the blinking cursor */}
      <style jsx="true">{`
        .cursor {
          display: inline-block;
          width: 10px;
          background-color: black;
          margin-left: 2px;
          animation: blink 1s step-start infinite;
        }

        @keyframes blink {
          50% {
            opacity: 0;
          }
        }
      `}</style>
    </Container>
  );
}

export default UserPage;