feat: add progress bar to lower jaw (#50167)

Co-authored-by: IsmailTlemcani <ismail.tlemcani@gmail.com>
Co-authored-by: ahmad abdolsaheb <ahmad.abdolsaheb@gmail.com>
This commit is contained in:
Sem Bauke
2023-06-06 13:59:40 +02:00
committed by GitHub
parent 30419c2e20
commit d18414fa2d
3 changed files with 103 additions and 16 deletions

View File

@@ -1,4 +1,5 @@
import React, { useState, useEffect, useRef } from 'react';
import React, { useState, useEffect, useRef, useMemo } from 'react';
import BezierEasing from 'bezier-easing';
interface ProgressBarInnerProps {
@@ -10,17 +11,37 @@ interface ProgressBarInnerProps {
const easing = BezierEasing(0.2, 0.5, 0.4, 1);
const intervalLength = 10;
let percent = 0;
let applyAnimation = true;
function useIsInViewport(ref: React.RefObject<HTMLDivElement>) {
const [isIntersecting, setIsIntersecting] = useState(false);
const observer = useMemo(
() =>
new IntersectionObserver(([entry]) =>
setIsIntersecting(entry.isIntersecting)
),
[]
);
useEffect(() => {
ref.current && observer.observe(ref.current);
return () => {
observer.disconnect();
};
}, [ref, observer]);
return isIntersecting;
}
function ProgressBarInner({
completedPercent,
title,
meta
}: ProgressBarInnerProps): JSX.Element {
const [shownPercent, setShownPercent] = useState(0);
const [progressInterval, setProgressInterval] = useState(0);
const [progressBarInnerWidth, setProgressBarInnerWidth] = useState(0);
const [lastShopwnPercent, setLastShownPercent] = useState(0);
const progressBarInnerWrap = useRef<HTMLDivElement>(null);
const isProgressBarInViewport = useIsInViewport(progressBarInnerWrap);
const animateProgressBarInner = (completedPercent: number) => {
if (completedPercent > 100) completedPercent = 100;
@@ -38,21 +59,19 @@ function ProgressBarInner({
setShownPercent(
Math.round(completedPercent * easing(percent / completedPercent))
);
if (percent >= completedPercent) clearInterval(myInterval);
if (percent >= completedPercent) {
percent = 0;
clearInterval(myInterval);
}
}, intervalLength);
setProgressInterval(myInterval);
};
useEffect(() => {
if (applyAnimation) animateProgressBarInner(completedPercent);
return () => {
if (progressInterval !== null) {
clearInterval(progressInterval);
applyAnimation = false;
}
};
if (lastShopwnPercent !== completedPercent && isProgressBarInViewport) {
setLastShownPercent(completedPercent);
animateProgressBarInner(completedPercent);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [completedPercent]);
}, [isProgressBarInViewport]);
useEffect(() => {
if (progressBarInnerWrap.current)

View File

@@ -9,7 +9,7 @@ import Help from '../../../assets/icons/help';
import Reset from '../../../assets/icons/reset';
import { MAX_MOBILE_WIDTH } from '../../../../../config/misc';
import { apiLocation } from '../../../../../config/env.json';
import ProgressBar from '../../../components/ProgressBar';
const lowerJawButtonStyle = 'btn-block btn';
interface LowerJawPanelProps {
@@ -310,6 +310,14 @@ const LowerJaw = ({
/>
)}
</div>
{challengeIsCompleted && (
<>
<hr></hr>
<div className='progress-bar-container'>
<ProgressBar />
</div>
</>
)}
<LowerButtonsPanel
resetButtonText={t('buttons.reset')}
helpButtonText={t('buttons.help')}

View File

@@ -5,7 +5,7 @@ describe('progress bar', () => {
});
it(
'Should show the progress bar showing the completed percent',
'Should show the progress bar showing the completed percent on legacy challenges',
{ browser: 'electron' },
() => {
cy.visit(
@@ -22,4 +22,64 @@ describe('progress bar', () => {
cy.get('.progress-bar-container').contains('1% complete');
}
);
it(
'Should show the progress bar showing the completed percent on modern challenges',
{ browser: 'electron' },
() => {
cy.visit(
'/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-2'
);
cy.get(`${'.react-monaco-editor-container'} textarea`, { timeout: 16000 })
.click()
.focused()
.type('{ctrl}a')
.clear()
.type(`<h1>CatPhotoApp</h1>\n<h2>Cat Photos</h2>`);
cy.contains('Check Your Code (Ctrl + Enter)').click({ force: true });
cy.contains('Submit and go to next challenge');
cy.get('.progress-bar-container').contains('1% complete');
}
);
it(
'Should show the progress bar showing the completed percent on modern challenges',
{ browser: 'electron' },
() => {
cy.visit(
'/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-3'
);
cy.get(`${'.react-monaco-editor-container'} textarea`, { timeout: 16000 })
.click()
.focused()
.type('{ctrl}a')
.clear()
.type(
`<h2>Cat Photos</h2>\n<p>See more cat photos in our gallery.</p>`
);
cy.contains('Check Your Code (Ctrl + Enter)').click({ force: true });
cy.contains('Submit and go to next challenge');
cy.get('.progress-bar-container').contains('1% complete');
}
);
it(
'Should show the progress bar showing the completed percent on modern challenges',
{ browser: 'electron' },
() => {
cy.visit(
'/learn/2022/responsive-web-design/learn-html-by-building-a-cat-photo-app/step-4'
);
cy.get(`${'.react-monaco-editor-container'} textarea`, { timeout: 16000 })
.click()
.focused()
.type('{ctrl}a')
.clear()
.type(
`<!-- TODO: Add link to cat photos -->\n<p>See more cat photos in our gallery.</p>`
);
cy.contains('Check Your Code (Ctrl + Enter)').click({ force: true });
cy.contains('Submit and go to next challenge');
cy.get('.progress-bar-container').contains('3% complete');
}
);
});