import BezierEasing from 'bezier-easing'; import React, { PureComponent } from 'react'; import { TFunction, withTranslation } from 'react-i18next'; import GreenPass from '../../../assets/icons/green-pass'; interface CompletionModalBodyProps { block: string; completedPercent: number; superBlock: string; t: TFunction; } interface CompletionModalBodyState { // This type was driving me nuts - seems like `NodeJS.Timeout | null;` should work // eslint-disable-next-line @typescript-eslint/no-explicit-any progressInterval: number | null; shownPercent: number; } export class CompletionModalBody extends PureComponent< CompletionModalBodyProps, CompletionModalBodyState > { static displayName: string; constructor(props: CompletionModalBodyProps) { super(props); this.state = { progressInterval: null, shownPercent: 0 }; this.animateProgressBar = this.animateProgressBar.bind(this); } animateProgressBar(completedPercent: number): void { const easing = BezierEasing(0.2, 0.5, 0.4, 1); if (completedPercent > 100) completedPercent = 100; if (completedPercent < 0) completedPercent = 0; const transitionLength = completedPercent * 10 + 750; const intervalLength = 10; const intervalsToFinish = transitionLength / intervalLength; const amountPerInterval = completedPercent / intervalsToFinish; let percent = 0; const myInterval = window.setInterval(() => { percent += amountPerInterval; if (percent > completedPercent) percent = completedPercent; this.setState({ shownPercent: Math.round( completedPercent * easing(percent / completedPercent) ) }); if (percent >= completedPercent) clearInterval(myInterval); }, intervalLength); this.setState({ progressInterval: myInterval }); } componentWillUnmount(): void { if (this.state.progressInterval !== null) clearInterval(this.state.progressInterval); } render(): JSX.Element { const { block, completedPercent, superBlock, t } = this.props; const blockTitle = t(`intro:${superBlock}.blocks.${block}.title`); return ( <>