Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added progress bar for the quiz #282

Merged
merged 6 commits into from
Jul 7, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ The quiz source is a JSON object. You can use [react-quiz-form](https://github.c
export const quiz = {
"quizTitle": "React Quiz Component Demo",
"quizSynopsis": "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim",
"progressBarColor": "#9de1f6",
"nrOfQuestions": "4",
"questions": [
{
Expand Down Expand Up @@ -279,6 +280,15 @@ import { quiz } from './quiz';
<Quiz quiz={quiz} timer={60} allowPauseTimer={true}/>
```


## Enable / Disable Progress Bar

```js
import { quiz } from './quiz';
...
<Quiz quiz={quiz} enableProgressBar={true} />
```

## Props

|Name|Type|Default|Required|Description|
Expand All @@ -295,6 +305,7 @@ import { quiz } from './quiz';
|disableSynopsis|`boolean`|`false`|N|Disable synopsis before quiz|
|timer|`number`|`false`|N|Sets timer in seconds|
|allowPauseTimer|`boolean`|`false`|N|Pause / Resume timer|
|enableProgressBar|`boolean`|`false`|N|Enable a progress bar|

## Contribution

Expand Down
1 change: 1 addition & 0 deletions src/docs/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ function App() {
disableSynopsis
timer={60}
allowPauseTimer
enableProgressBar
/>
</div>
);
Expand Down
1 change: 1 addition & 0 deletions src/docs/quiz.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const quiz = {
quizTitle: 'React Quiz Component Demo',
quizSynopsis: 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim',
nrOfQuestions: '6',
progressBarColor: '#9de1f6',
questions: [
{
question: 'How can you access the state of a component from inside of a member function?',
Expand Down
16 changes: 15 additions & 1 deletion src/lib/Core.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, {
useState, useEffect, useCallback, Fragment,
} from 'react';
import { nanoid } from 'nanoid';
import ProgressBar from './core-components/ProgressBar';
import QuizResultFilter from './core-components/QuizResultFilter';
import { checkAnswer, selectAnswer, rawMarkup } from './core-components/helpers';
import InstantFeedback from './core-components/InstantFeedback';
Expand All @@ -10,7 +11,7 @@ import Explanation from './core-components/Explanation';
function Core({
questions, appLocale, showDefaultResult, onComplete, customResultPage,
showInstantFeedback, continueTillCorrect, revealAnswerOnSubmit, allowNavigation,
onQuestionSubmit, timer, allowPauseTimer,
onQuestionSubmit, timer, allowPauseTimer, enableProgressBar, progressBarColor
}) {
const [incorrectAnswer, setIncorrectAnswer] = useState(false);
const [isCorrect, setIsCorrect] = useState(false);
Expand Down Expand Up @@ -391,6 +392,19 @@ function Core({

return (
<div className="questionWrapper">
{enableProgressBar && (
<>
<div style={{ display: 'flex', width: '100%' }}>
<ProgressBar
progress={currentQuestionIndex + 1}
quizLength={questions.length}
isEndQuiz={endQuiz}
progressBarColor={progressBarColor}
/>
</div>
<br />
</>
)}
{timer && !isRunning && (
<div>
{appLocale.timerTimeTaken}
Expand Down
25 changes: 25 additions & 0 deletions src/lib/Quiz.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ function Quiz({
disableSynopsis,
timer,
allowPauseTimer,
enableProgressBar,
}) {
const [start, setStart] = useState(false);
const [questions, setQuestions] = useState(quiz.questions);
Expand Down Expand Up @@ -92,6 +93,11 @@ function Quiz({
setQuestions(newQuestions);
}, [start]);

const validateProgressBarColor = (inputColor) => {
const hexaPattern = /^#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/;
return hexaPattern.test(inputColor);
};

const validateQuiz = (q) => {
if (!q) {
console.error('Quiz object is required.');
Expand All @@ -108,6 +114,23 @@ function Quiz({
return false;
}

if (enableProgressBar && typeof enableProgressBar !== 'boolean') {
console.error('enableProgressBar must be a Boolean');
return false;
}

if ('progressBarColor' in quiz) {
if (typeof quiz.progressBarColor !==) {
wingkwong marked this conversation as resolved.
Show resolved Hide resolved
console.error('progressBarColor must be a String');
return false;
}

if (!validateProgressBarColor(quiz.progressBarColor)) {
console.error('progressBarColor must be a valid hex colour');
return false;
}
}

for (let i = 0; i < questions.length; i += 1) {
const {
question,
Expand Down Expand Up @@ -222,6 +245,8 @@ function Quiz({
onQuestionSubmit={onQuestionSubmit}
timer={timer}
allowPauseTimer={allowPauseTimer}
enableProgressBar={enableProgressBar}
progressBarColor={quiz.progressBarColor}
/>
)}
</div>
Expand Down
50 changes: 50 additions & 0 deletions src/lib/core-components/ProgressBar.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';

const ProgressBar = ({ progressBarColor, progress, height, quizLength, isEndQuiz }) => {
const fixedProgress = progress - 1;
const progressUnit = 100 / quizLength;

const progressBarContainer = {
width: '100%',
backgroundColor: '#D0D4CA',
height: height,
borderRadius: 40,
position: 'relative',
overflow: 'hidden',
};

const progressBar = {
width: isEndQuiz ? `100%` : `${progressUnit * fixedProgress}%`,
height: '100%',
backgroundColor: progressBarColor,
transition: 'width 0.3s ease',
};

const progressBarLabel = {
position: 'absolute',
left: '50%',
top: '50%',
transform: 'translateX(-50%) translateY(-50%)',
lineHeigth: '20px',
fontSize: '16px',
color: '#000',
fontWeight: 'bold',
backgroundColor: 'transparent',
};

return (
<div style={progressBarContainer}>
<div style={progressBar} />
<span style={progressBarLabel}>
{isEndQuiz ? '100%' : `${Math.round(progressUnit * fixedProgress)}%`}
</span>
</div>
);
};

ProgressBar.defaultProps = {
progressBarColor: '#9de1f6', // Set a default value for background color
height: '25px', // Set a default value for bar's height
};

export default ProgressBar;