All files / app/components CustomColorSwitch.tsx

100% Statements 17/17
92.59% Branches 25/27
100% Functions 6/6
100% Lines 17/17

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 1123x 3x 3x   3x                   3x 138x 27x                           3x   3x 246x 27x                                                       28x               45x   45x 18x                                       45x 18x                                  
import { styled, Switch, SwitchProps } from "@mui/material";
import { useEffect, useState } from "react";
import { theme } from "theme";
 
import CircularProgress from "./CircularProgress";
 
interface CustomSwitchProps extends Omit<SwitchProps, "color"> {
  checked: boolean;
  customColor?: string; // renamed to avoid conflict with existing color prop
  size?: SwitchProps["size"];
  status?: string;
  isLoading?: boolean;
}
 
const StyledCircle = styled("div", {
  shouldForwardProp: (prop) => prop !== "customColor" && prop !== "isLoading",
})<CustomSwitchProps>(({ theme, size, checked, customColor, isLoading }) => ({
  display: "flex",
  alignItems: "center",
  justifyContent: "center",
  width: size === "medium" ? 20 : 16,
  height: size === "medium" ? 20 : 16,
  borderRadius: "50%",
  backgroundColor: checked ? customColor : theme.palette.grey[600],
  boxShadow: theme.shadows[1],
  ...(isLoading && {
    backgroundColor: theme.palette.grey[400], // Change color when loading
  }),
}));
 
const dontPassProps = ["customColor", "isLoading", "status"];
 
const StyledSwitch = styled(Switch, {
  shouldForwardProp: (prop) => !dontPassProps.includes(prop as string), // Filter out props that shouldn't be forwarded
})<CustomSwitchProps>(({ theme, customColor, checked, isLoading, status }) => ({
  "& .MuiSwitch-switchBase": {
    color: theme.palette.grey[600],
    "& + .MuiSwitch-track": {
      backgroundColor: theme.palette.grey[200],
    },
    "&.Mui-checked": {
      color: customColor,
      "& + .MuiSwitch-track": {
        backgroundColor: customColor,
      },
    },
    "&.Mui-disabled": {
      color: checked ? customColor : theme.palette.grey[600],
      "& + .MuiSwitch-track": {
        backgroundColor: checked ? customColor : theme.palette.grey[200],
        opacity: 0.4,
      },
    },
  },
  ...(isLoading || status === "loading"
    ? {
        opacity: 0.5, // Reduce opacity when loading or status is "loading"
        pointerEvents: "none", // Disable interaction when loading
      }
    : {}),
}));
 
export default function CustomColorSwitch({
  checked,
  onClick,
  size = "medium",
  status,
  isLoading = false,
  customColor = theme.palette.secondary.main, // renamed to customColor to avoid conflict with MUI Switch color
}: CustomSwitchProps) {
  const [isMounted, setIsMounted] = useState(false);
 
  useEffect(() => {
    setIsMounted(true);
  }, []);
 
  const Icon = () => (
    <StyledCircle
      size={size}
      checked={checked}
      customColor={customColor}
      isLoading={isLoading}
    >
      {isLoading && (
        <CircularProgress
          size={size === "medium" ? 14 : 12}
          style={{ color: "white" }}
          thickness={6}
        />
      )}
    </StyledCircle>
  );
 
  if (!isMounted) {
    return null;
  }
 
  return (
    <StyledSwitch
      checked={checked}
      checkedIcon={<Icon />}
      disabled={isLoading || status === "loading"}
      icon={<Icon />}
      onClick={onClick}
      size={size}
      customColor={customColor} // Pass customColor prop to StyledSwitch
      isLoading={isLoading}
      status={status}
    />
  );
}