2024-08-25 16:14:33 +02:00

65 lines
1.8 KiB
TypeScript

import React, { useCallback, useEffect, useRef, useState } from "react";
import Typography, { ETypo, ETypoColor } from "../Typography";
import classes from "./classes.module.scss";
import classNames from "classnames";
type IProps = {
percentage: number;
className?: string;
};
export default function CircleProgress(props: IProps) {
const { percentage, className } = props;
const [animatedProgress, setAnimatedProgress] = useState(0);
const requestRef = useRef<number>();
const animate = useCallback(() => {
setAnimatedProgress((prev) => {
if (prev < percentage) {
return prev + 1;
} else {
if (requestRef.current) {
cancelAnimationFrame(requestRef.current);
}
return prev;
}
});
requestRef.current = requestAnimationFrame(animate);
}, [percentage]);
useEffect(() => {
setAnimatedProgress(0); // Reset progress
requestRef.current = requestAnimationFrame(animate);
return () => {
if (requestRef.current) {
cancelAnimationFrame(requestRef.current);
}
};
}, [percentage, animate]);
const radius = 11;
const circumference = 2 * Math.PI * radius;
const offset = circumference - (animatedProgress / 100) * circumference;
return (
<div className={classNames(classes["root"], className)}>
<svg xmlns="http://www.w3.org/2000/svg" width="27" height="27" viewBox="0 0 27 27" fill="none">
<circle className={classes["circleBackground"]} cx="13.5" cy="13.5" r={radius} strokeWidth="3" />
<circle
className={classes["circleProgress"]}
cx="13.5"
cy="13.5"
r={radius}
strokeWidth="3"
strokeDasharray={circumference}
strokeDashoffset={offset}
/>
</svg>
<Typography typo={ETypo.TEXT_LG_REGULAR} color={ETypoColor.COLOR_NEUTRAL_950}>
{Math.round(percentage)}%
</Typography>
</div>
);
}