Skip to content
Snippets Groups Projects
Commit 033e8aeb authored by Saket Agrahari's avatar Saket Agrahari
Browse files

Merge branch 'feature/COMP-213-progress-bar' into 'develop'

COMP-213: progress bar

See merge request !46
parents 6406643a 4dbc8269
Branches
Tags
1 merge request!46COMP-213: progress bar
import React from "react";
function ProgressBar({
completionPercentage,
unansweredPercentage,
pages,
pageTitle,
}) {
const progressBarContainerStyle: React.CSSProperties = {
display: "flex",
flexWrap: "wrap",
height: "10px",
margin: "5px",
width: `${100 / pages}%`,
};
const progressBarFillStyle: React.CSSProperties = {
height: "100%",
transition: "width 0.3s ease",
};
const progressBarFillStyleCopy: React.CSSProperties = {
...progressBarFillStyle,
width: `${completionPercentage}%`,
backgroundColor: "#1ab394",
};
const unansweredProgressBarFillStyle: React.CSSProperties = {
...progressBarFillStyle,
width: `${unansweredPercentage}%`,
backgroundColor: "#9d9d9d",
};
const pageTitleStyle: React.CSSProperties ={
width: "100%",
textAlign: "center"
}
return (
<div style={progressBarContainerStyle}>
<div style={progressBarFillStyleCopy} />
<div style={unansweredProgressBarFillStyle} />
<div style={pageTitleStyle}>{pageTitle}</div>
</div>
);
}
export default ProgressBar;
......@@ -3,11 +3,17 @@ import { Model, Serializer, ComputedUpdater, Question } from "survey-core";
import { Survey } from "survey-react-ui";
import "survey-core/modern.min.css";
import './survey.scss';
import ProgressBar from "./ProgressBar";
Serializer.addProperty("itemvalue", "customDescription:text");
Serializer.addProperty("question", "hideCheckboxLabels:boolean");
interface Progress {
completionPercentage: number;
unansweredPercentage: number;
totalPages: number;
pageTitle: string;
}
enum VerificationStatus {
New = "new", // a question that was not answered last year
Answered = "answered", // a question that was not answered last year but has an answer now
......@@ -18,9 +24,9 @@ enum VerificationStatus {
function SurveyComponent() {
const [surveyModel, setSurveyModel] = useState<Model>();
const verificationStatus = useRef<Map<string, VerificationStatus>>(new Map());
const [surveyModel, setSurveyModel] = useState<Model>();
const [progress, setProgress] = useState<Progress[]>([]);
const verificationStatus = useRef<Map<string, VerificationStatus>>(new Map());
function setVerifyButton(question: Question, state: VerificationStatus) {
......@@ -52,9 +58,9 @@ function SurveyComponent() {
}
}
// const surveyComplete = useCallback((sender) => {
// console.log(sender.data);
// }, []);
// const surveyComplete = useCallback((sender) => {
// console.log(sender.data);
// }, []);
async function getModel()
{
......@@ -67,10 +73,9 @@ function SurveyComponent() {
const survey = new Model(json['model']);
if (json['data'] !== null)
{
survey.data = json['data'];
}
if (json['data'] !== null) {
survey.data = json['data'];
}
// TODO also use data and page info
......@@ -103,25 +108,24 @@ function SurveyComponent() {
innerCss: "sv-btn sv-btn--navigation sv-footer__complete-btn"
});
survey.onComplete.add((sender, options) => {
console.log(sender.data)
options.showSaveInProgress();
const xhr = new XMLHttpRequest();
xhr.open("POST", "/api/survey/save");
xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
xhr.onload = xhr.onerror = function () {
if (xhr.status == 200) {
// Display the "Success" message (pass a string value to display a custom message)
options.showSaveSuccess();
// Alternatively, you can clear all messages:
// options.clearSaveMessages();
} else {
// Display the "Error" message (pass a string value to display a custom message)
options.showSaveError();
}
};
survey.onComplete.add((sender, options) => {
console.log(sender.data);
options.showSaveInProgress();
const xhr = new XMLHttpRequest();
xhr.open("POST", "/api/survey/save");
xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
xhr.onload = xhr.onerror = function () {
if (xhr.status == 200) {
// Display the "Success" message (pass a string value to display a custom message)
options.showSaveSuccess();
// Alternatively, you can clear all messages:
// options.clearSaveMessages();
} else {
// Display the "Error" message (pass a string value to display a custom message)
options.showSaveError();
}
};
const saveData = {
data: sender.data,
......@@ -133,9 +137,8 @@ function SurveyComponent() {
survey.onPartialSend.add((sender, options) => {
console.log(sender.data)
// TODO same as above
});
// TODO same as above
});
survey.onAfterRenderQuestion.add(function(survey, options){
const status = verificationStatus.current.get(options.question.name);
......@@ -160,38 +163,90 @@ function SurveyComponent() {
}
});
survey.onMatrixAfterCellRender.add((survey, options) => {
// get the customDescription for matrix rows and set it in the title
// attribute so that it shows up as a hover popup
// NB I would have preferred using onAfterRenderQuestion, but unfortunately that is
// not always triggered on re-renders (specifically when extra column become visble or invisible)
if (options.column['indexValue'] == 0 && 'item' in options.row) {
const item = options.row['item'] as object;
if (item['customDescription'] !== undefined) {
options.htmlElement.parentElement?.children[0].setAttribute("title", item['customDescription']);
}
}
survey.onMatrixAfterCellRender.add((survey, options) => {
// get the customDescription for matrix rows and set it in the title
// attribute so that it shows up as a hover popup
// NB I would have preferred using onAfterRenderQuestion, but unfortunately that is
// not always triggered on re-renders (specifically when extra column become visble or invisible)
if (options.column['indexValue'] == 0 && 'item' in options.row) {
const item = options.row['item'] as object;
if (item['customDescription'] !== undefined) {
options.htmlElement.parentElement?.children[0].setAttribute(
"title",
item['customDescription']
);
}
}
});
survey.onCurrentPageChanged.add((sender) => {
console.log("sender--> " + sender);
calculateProgress(sender);
});
setSurveyModel(survey);
}
const filterCallback = (question) => {
return question.value !== null && question.value !== undefined;
};
const calculateProgress = (survey) => {
// console.log("survey--> "+ survey);
if (survey && survey.pages) {
console.log("survey.page--> " + survey.pages);
const progressArray: Progress[] = [];
survey.pages.forEach((page) => {
const sectionQuestions = page.questions.filter(
(question) => question.startWithNewLine
);
const questionCount = sectionQuestions.length;
const answeredCount = sectionQuestions.filter(filterCallback).length;
const unansweredCount = questionCount - answeredCount;
const completionPercentage = answeredCount / questionCount;
progressArray.push({
completionPercentage: completionPercentage * 100,
unansweredPercentage: (unansweredCount / questionCount) * 100,
totalPages: survey.pages.length,
pageTitle: page.title,
});
setSurveyModel(survey);
});
setProgress(progressArray);
}
};
useEffect(() => {
getModel();
}, []);
useEffect(() => {
getModel();
}, []);
if (surveyModel)
{
return (<Survey model={surveyModel} />);
useEffect(() => {
if (surveyModel) {
calculateProgress(surveyModel);
}
else
{
return (<span>loading...</span>);
}
}, [surveyModel]);
if (surveyModel) {
return (
<div className="survey-container">
<div className="survey-progress">
{progress.map((sectionProgress, index) => (
<ProgressBar
key={index}
completionPercentage={sectionProgress.completionPercentage}
unansweredPercentage={sectionProgress.unansweredPercentage}
pages={sectionProgress.totalPages}
pageTitle={sectionProgress.pageTitle}
/>
))}
</div>
<Survey model={surveyModel} />
</div>
);
} else {
return <span>loading...</span>;
}
}
export default SurveyComponent;
\ No newline at end of file
export default SurveyComponent;
......@@ -24,4 +24,8 @@
.sv-action-bar-item.verification.verification-ok:hover {
cursor: auto;
background-color: transparent;
}
.survey-progress {
display: flex;
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment