Analyze critically the following js react component for rendering mathematical shapes:

import React, { useEffect, useRef, useState } from 'react';

const ShapeRenderer = ({ shapes }) => {
  const canvasRef = useRef(null);
  const [currentIndex, setCurrentIndex] = useState(0);

  const getTopMostPoint = (shape, startX, startY) => {
    switch (shape.type) {
      case 'rectangle':
        return startY - shape.height / 2;
      case 'square':
        return startY - shape.side / 2;
      case 'circle':
        return startY - shape.radius;
      case 'ellipse':
        return startY - shape.radiusY;
      case 'triangle':
        return startY - Math.min(shape.height / 2, startY - (startY + shape.height / 2) + (shape.base / 2) * Math.tan(Math.PI / 6)); 
      case 'equilateralTriangle':
        return startY - (Math.sqrt(3) / 4) * shape.side;
      case 'isoscelesTriangle':
        return startY - shape.height / 2;
      case 'hexagon':
      case 'pentagon':
        return startY - shape.side * Math.cos(Math.PI / 6);
      case 'rotatedHexagon':
        return startY - shape.side;
      case 'rightAngledTriangle':
        return startY - shape.height / 2; 
      case 'inscribed':
        return getTopMostPoint({ ...shape, type: shape.outerShape }, startX, startY);
      case 'surrounded':
        if (shape.outerShape === 'square') {
          return startY - shape.outerSide / 2;
        } else if (shape.outerShape === 'rightAngledTriangle') {
          return startY - shape.outerHeight / 2;
        }
      default:
        return startY - 60; 
    }
  };

  useEffect(() => {
    const canvas = canvasRef.current;
    const ctx = canvas.getContext('2d');
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    const shape = shapes[currentIndex];
    if (shape) {
      ctx.beginPath();
      ctx.strokeStyle = shape.type === 'inscribed' || shape.type === 'surrounded' ? 'black' : (shape.color || 'black');

      // Calculate the starting point for the shape
      const startX = canvas.width / 2;
      const startY = canvas.height / 2;
      const sideLabels = getSideLabelPositions(shape, startX, startY);
      ctx.fillStyle = 'black';
      ctx.font = '14px Arial';
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';
      sideLabels.forEach(label => {
        ctx.fillText(label.label, label.x, label.y);
      });

      let topMostPoint;

      switch (shape.type) {
        case 'rectangle':
          ctx.rect(startX - shape.width / 2, startY - shape.height / 2, shape.width, shape.height);
          break;
        case 'circle':
          ctx.arc(startX, startY, shape.radius, 0, 2 * Math.PI);
          break;
        case 'triangle':
          ctx.moveTo(startX, startY - shape.height / 2);
          ctx.lineTo(startX + shape.base / 2, startY + shape.height / 2);
          ctx.lineTo(startX - shape.base / 2, startY + shape.height / 2);
          ctx.closePath();
          break;
        case 'square':
          ctx.rect(startX - shape.side / 2, startY - shape.side / 2, shape.side, shape.side);
          break;
        case 'hexagon':
          drawHexagon(ctx, startX, startY, shape.side);
          break;
        case 'ellipse':
          drawEllipse(ctx, startX, startY, shape.radiusX, shape.radiusY);
          break;
        case 'pentagon':
          drawPentagon(ctx, startX, startY, shape.side);
          break;
        case 'equilateralTriangle':
          drawEquilateralTriangle(ctx, startX, startY, shape.side);
          break;
        case 'isoscelesTriangle':
          drawIsoscelesTriangle(ctx, startX, startY, shape.base, shape.height);
          break;
        case 'rightAngledTriangle':
          drawRightAngledTriangle(ctx, startX, startY, shape.base, shape.height);
          break;
        case 'rotatedHexagon':
          drawRotatedHexagon(ctx, startX, startY, shape.side, shape.rotation);
          break;
        case 'inscribed':
        case 'surrounded':
          topMostPoint = drawInscribedShapes(ctx, startX, startY, shape);
          break;
        default:
          console.warn(`Unknown shape type: ${shape.type}`);
      }

      ctx.stroke();

      if (topMostPoint === undefined) {
        topMostPoint = getTopMostPoint(shape, startX, startY);
      }

      ctx.fillStyle = 'black';
      ctx.font = '16px Arial';
      ctx.textAlign = 'center';
      ctx.fillText(shape.label, startX, topMostPoint - 50);
    }
  }, [shapes, currentIndex]);

  const drawHexagon = (ctx, x, y, side) => {
    const angle = (2 * Math.PI) / 6;
    ctx.moveTo(x + side * Math.cos(0), y + side * Math.sin(0));
    for (let i = 1; i <= 6; i++) {
      ctx.lineTo(x + side * Math.cos(i * angle), y + side * Math.sin(i * angle));
    }
    ctx.closePath();
  };

  const drawEllipse = (ctx, x, y, radiusX, radiusY) => {
    ctx.ellipse(x, y, radiusX, radiusY, 0, 0, 2 * Math.PI);
  };

  const drawPentagon = (ctx, x, y, side) => {
    const angle = (2 * Math.PI) / 5;
    ctx.moveTo(x + side * Math.cos(0), y + side * Math.sin(0));
    for (let i = 1; i <= 5; i++) {
      ctx.lineTo(x + side * Math.cos(i * angle), y + side * Math.sin(i * angle));
    }
    ctx.closePath();
  };

  const drawEquilateralTriangle = (ctx, x, y, side) => {
    const height = (Math.sqrt(3) / 2) * side;
    ctx.moveTo(x, y - height / 2);
    ctx.lineTo(x + side / 2, y + height / 2);
    ctx.lineTo(x - side / 2, y + height / 2);
    ctx.closePath();
  };

  const drawIsoscelesTriangle = (ctx, x, y, base, height) => {
    ctx.moveTo(x, y - height / 2);
    ctx.lineTo(x + base / 2, y + height / 2);
    ctx.lineTo(x - base / 2, y + height / 2);
    ctx.closePath();
  };

  const drawRightAngledTriangle = (ctx, x, y, base, height) => {
    ctx.moveTo(x + base / 2, y + height / 2);
    ctx.lineTo(x - base / 2, y + height / 2);
    ctx.lineTo(x + base / 2, y - height / 2);
    ctx.closePath();
  };

  const drawRotatedHexagon = (ctx, x, y, side, rotation) => {
    const angle = (2 * Math.PI) / 6;
    ctx.translate(x, y);
    ctx.rotate((rotation * Math.PI) / 180);
    ctx.moveTo(side * Math.cos(0), side * Math.sin(0));
    for (let i = 1; i <= 6; i++) {
      ctx.lineTo(side * Math.cos(i * angle), side * Math.sin(i * angle));
    }
    ctx.closePath();
    ctx.rotate((-rotation * Math.PI) / 180);
    ctx.translate(-x, -y);
  };

  const getDimensionLabels = (shape) => {
    switch (shape.type) {
      case 'rectangle':
        return { width: shape.width, height: shape.height };
      case 'circle':
        return { radius: shape.radius };
      case 'equilateralTriangle':
      case 'square':
        return { side: shape.side };
      case 'ellipse':
        return { radiusX: shape.radiusX, radiusY: shape.radiusY };
      case 'triangle':
      case 'isoscelesTriangle':
        return { base: shape.base, height: shape.height };
      case 'hexagon':
      case 'pentagon':
      case 'rotatedHexagon':
        return { side: shape.side };
      case 'rightAngledTriangle':
        return { base: shape.base, height: shape.height };
      default:
        return {};
    }
  };

  const getSideLabelPositions = (shape, startX, startY) => {
    const dimensions = getDimensionLabels(shape);
    switch (shape.type) {
      case 'rectangle':
        return [
          { x: startX - dimensions.width / 2, y: startY, label: dimensions.width },
          { x: startX, y: startY - dimensions.height / 2, label: dimensions.height },
        ];
      case 'square':
        return [
          { x: startX, y: startY + dimensions.side / 2 + 15, label: dimensions.side },
        ];
      case 'circle':
        return [
          { x: startX + dimensions.radius, y: startY, label: `r=${dimensions.radius}` },
        ];
      case 'equilateralTriangle':
        return [
          { x: startX, y: startY + (Math.sqrt(3) / 4) * dimensions.side + 15, label: dimensions.side },
        ];
      case 'ellipse':
        return [
          { x: startX + dimensions.radiusX, y: startY, label: `rx=${dimensions.radiusX}` },
          { x: startX, y: startY - dimensions.radiusY, label: `ry=${dimensions.radiusY}` },
        ];
      case 'triangle':
      case 'isoscelesTriangle':
      case 'rightAngledTriangle':
        return [
          { x: startX, y: startY + dimensions.height / 2 + 15, label: dimensions.base },
          { x: startX - dimensions.base / 2 - 15, y: startY, label: dimensions.height },
        ];
      case 'hexagon':
      case 'pentagon':
      case 'rotatedHexagon':
        return [
          { x: startX + dimensions.side / 2, y: startY + dimensions.side * Math.sin(Math.PI / 3) + 15, label: dimensions.side },
        ];
      default:
        return [];
    }
  };

  const drawInscribedShapes = (ctx, x, y, shape) => {
    const { outerShape, innerShape, outerSide, innerSide, radius, width, height, side, outerBase, outerHeight, innerBase, innerHeight, shaded, outerLabel, innerLabel } = shape;

    const outerColor = 'rgba(200, 200, 200, 0.5)';
    const innerColor = 'rgba(100, 100, 255, 0.5)';
    const shadedColor = 'rgba(100, 100, 100, 0.7)';
    
    ctx.beginPath();
    ctx.strokeStyle = 'black';
    let outerBoundingBox = { x: x, y: y, width: 0, height: 0 };
    switch (outerShape) {
      case 'square':
        outerBoundingBox = { x: x - (outerSide || side) / 2, y: y - (outerSide || side) / 2, width: outerSide || side, height: outerSide || side };
        ctx.rect(outerBoundingBox.x, outerBoundingBox.y, outerBoundingBox.width, outerBoundingBox.height);
        break;
      case 'circle':
        outerBoundingBox = { x: x - radius, y: y - radius, width: radius * 2, height: radius * 2 };
        ctx.arc(x, y, radius, 0, 2 * Math.PI);
        break;
      case 'hexagon':
        outerBoundingBox = { x: x - (outerSide || side), y: y - (outerSide || side) * Math.sqrt(3) / 2, width: (outerSide || side) * 2, height: (outerSide || side) * Math.sqrt(3) };
        drawHexagon(ctx, x, y, outerSide || side);
        break;
      case 'rectangle':
        outerBoundingBox = { x: x - width / 2, y: y - height / 2, width: width, height: height };
        ctx.rect(outerBoundingBox.x, outerBoundingBox.y, outerBoundingBox.width, outerBoundingBox.height);
        break;
      case 'rightAngledTriangle':
        outerBoundingBox = { x: x - outerBase / 2, y: y - outerHeight / 2, width: outerBase, height: outerHeight };
        drawRightAngledTriangle(ctx, x, y, outerBase, outerHeight);
        break;
      default:
        console.warn(`Unknown outer shape type: ${outerShape}`);
    }
    ctx.fillStyle = shaded === 'outer' ? shadedColor : outerColor;
    ctx.fill();
    ctx.stroke();

    // Draw inner shape
    ctx.beginPath();
    ctx.strokeStyle = 'blue';
    let innerBoundingBox = { x: x, y: y, width: 0, height: 0 };
    switch (innerShape) {
      case 'circle':
        if (outerShape === 'hexagon') {
          const innerRadius = (outerSide || side) * Math.sqrt(3) / 2;
          innerBoundingBox = { x: x - innerRadius, y: y - innerRadius, width: innerRadius * 2, height: innerRadius * 2 };
          ctx.arc(x, y, innerRadius, 0, 2 * Math.PI);
        } else {
          innerBoundingBox = { x: x - (outerSide || side) / 2, y: y - (outerSide || side) / 2, width: outerSide || side, height: outerSide || side };
          ctx.arc(x, y, (outerSide || side) / 2, 0, 2 * Math.PI);
        }
        break;
      case 'square':
        if (shape.type === 'surrounded' && outerShape === 'square') {
          innerBoundingBox = { x: x - innerSide / 2, y: y - innerSide / 2, width: innerSide, height: innerSide };
          ctx.rect(innerBoundingBox.x, innerBoundingBox.y, innerBoundingBox.width, innerBoundingBox.height);
        } else if (outerShape === 'circle') {
          const innerSideLength = radius * Math.sqrt(2);
          innerBoundingBox = { x: x - innerSideLength / 2, y: y - innerSideLength / 2, width: innerSideLength, height: innerSideLength };
          ctx.rect(innerBoundingBox.x, innerBoundingBox.y, innerBoundingBox.width, innerBoundingBox.height);
        } else if (outerShape === 'rectangle' || outerShape === 'square') {
          innerBoundingBox = { x: x - (innerSide || side) / 2, y: y - (innerSide || side) / 2, width: innerSide || side, height: innerSide || side };
          ctx.rect(innerBoundingBox.x, innerBoundingBox.y, innerBoundingBox.width, innerBoundingBox.height);
        } else if (outerShape === 'hexagon') {
          innerBoundingBox = { x: x - innerSide / 2, y: y - innerSide / 2, width: innerSide, height: innerSide };
          ctx.rect(innerBoundingBox.x, innerBoundingBox.y, innerBoundingBox.width, innerBoundingBox.height);
        } else {
          const innerSideLength = radius * Math.sqrt(2);
          innerBoundingBox = { x: x - innerSideLength / 2, y: y - innerSideLength / 2, width: innerSideLength, height: innerSideLength };
          ctx.rect(innerBoundingBox.x, innerBoundingBox.y, innerBoundingBox.width, innerBoundingBox.height);
        }
        break;
      case 'hexagon':
        if (outerShape === 'circle') {
          innerBoundingBox = { x: x - radius, y: y - radius * Math.sqrt(3) / 2, width: radius * 2, height: radius * Math.sqrt(3) };
          drawHexagon(ctx, x, y, radius);
        } else {
          const hexRadius = (outerSide || side) / (2 * Math.sin(Math.PI / 6));
          innerBoundingBox = { x: x - hexRadius, y: y - hexRadius * Math.sqrt(3) / 2, width: hexRadius * 2, height: hexRadius * Math.sqrt(3) };
          drawHexagon(ctx, x, y, hexRadius);
        }
        break;
      case 'rightAngledTriangle':
        if (outerShape === 'rightAngledTriangle') {
          innerBoundingBox = { x: x + (outerBase - innerBase) / 2 - innerBase / 2, y: y - outerHeight / 2, width: innerBase, height: outerHeight };
          drawRightAngledTriangle(ctx, x + (outerBase - innerBase) / 2, y, innerBase, outerHeight);
        } else {
          console.warn('Right-angled triangle can only be inscribed in another right-angled triangle');
        }
        break;
      default:
        console.warn(`Unknown inner shape type: ${innerShape}`);
    }
    ctx.fillStyle = shaded === 'inner' ? shadedColor : innerColor;
    ctx.fill();
    ctx.stroke();

    // Draw labels
    ctx.fillStyle = 'black';
    ctx.font = '14px Arial';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';

    // Calculate label positions
    const outerLabelPos = calculateLabelPosition(outerBoundingBox, 'outer');
    const innerLabelPos = calculateLabelPosition(innerBoundingBox, 'inner');

    // Draw outer label
    if (typeof outerLabel === 'string') {
      ctx.fillText(outerLabel, outerLabelPos.x, outerLabelPos.y);
    } else if (typeof outerLabel === 'object') {
      Object.entries(outerLabel).forEach(([key, value], index) => {
        ctx.fillText(value, outerLabelPos.x, outerLabelPos.y + index * 20);
      });
    }

    // Draw inner label
    if (typeof innerLabel === 'string') {
      ctx.fillText(innerLabel, innerLabelPos.x, innerLabelPos.y);
    } else if (typeof innerLabel === 'object') {
      Object.entries(innerLabel).forEach(([key, value], index) => {
        ctx.fillText(value, innerLabelPos.x, innerLabelPos.y + index * 20);
      });
    }

    // Calculate and return the top-most point of the outer shape
    return getTopMostPoint(shape, x, y);
  };

  function calculateLabelPosition(boundingBox, type) {
    const padding = 10;
    let x, y;

    if (type === 'outer') {
      x = boundingBox.x + boundingBox.width / 2;
      y = boundingBox.y - padding;
    } else {
      x = boundingBox.x + boundingBox.width / 2;
      y = boundingBox.y + boundingBox.height + padding;
    }

    return { x, y };
  }

  const handleNext = () => {
    setCurrentIndex((prevIndex) => (prevIndex + 1) % shapes.length);
  };

  const handlePrevious = () => {
    setCurrentIndex((prevIndex) => (prevIndex - 1 + shapes.length) % shapes.length);
  };

  return (
    <div>
      <canvas
        ref={canvasRef}
        width={window.innerWidth}
        height={window.innerHeight}
        style={{ border: '1px solid black' }}
      />
      <div>
        <button onClick={handlePrevious} disabled={currentIndex === 0}>Previous</button>
        <button onClick={handleNext} disabled={currentIndex === shapes.length - 1}>Next</button>
      </div>
    </div>
  );
};

export default ShapeRenderer;