Skip to content
Snippets Groups Projects
Commit c2a57cff authored by Remco Tukker's avatar Remco Tukker
Browse files

keep track of all verification statuses and add some basic styling

parent aaead1a9
Branches
Tags
1 merge request!45Feature/comp 214 verification of last years answers
import json
import logging
from enum import Enum
from pathlib import Path
from typing import Any, List, Optional
from typing import Any, Optional
from flask import Blueprint, jsonify, request
from sqlalchemy import select
......@@ -18,6 +19,13 @@ logger = logging.getLogger(__name__)
# TODO (partial) schemas
class VerificationStatus(str, Enum):
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
Unverified = "unverified" # a question that has its answered copied from last year
Verified = "verified" # a question for which last years answer was verified
Edited = "edited" # a question for which last years answer was edited
@routes.route('/open', methods=['GET'])
@common.require_accepts_json
......@@ -25,7 +33,7 @@ def open_survey() -> Any:
# just a hardcoded year and nren for development for now
nren = db.session.execute(select(NREN).order_by(NREN.id).limit(1)).scalar_one()
year = 1988
year = 1989
survey = db.session.scalar(select(Survey).where(Survey.year == year))
if survey is None or survey.survey == {}:
......@@ -39,10 +47,7 @@ def open_survey() -> Any:
data: Optional[dict] = None
page = 0
unverified: List[str] = [] # or should we keep track of what _was_ validated? nah in that case we also
# need to track what needs validation, easier to just encode that in the 'unvalidated' list
# the only difference it really makes is when question identifiers change etc, in which
# case there may be copied data without a question
verification_status: dict[str, str] = {"budget": VerificationStatus.Unverified, "TODO": "remove or set everything to new"}
response = db.session.scalar(
select(SurveyResponse).where(SurveyResponse.survey_year == year).where(SurveyResponse.nren_id == nren.id)
......@@ -54,19 +59,19 @@ def open_survey() -> Any:
if response:
data = response.answers["data"]
page = response.answers["page"]
unverified = response.answers["unverified"]
verification_status = response.answers["verification_status"]
elif previous_response:
# TODO add a 'migration' hook here for updating data per year
# TODO i suppose we also need to remove the data that isnt asked anymore because
# i dont think the frontend will remove it
data = previous_response.answers["data"]
unverified = ["TODO everything that was copied?"]
verification_status = {"budget": VerificationStatus.Unverified, "TODO": "all other questions"}
open_survey: dict = {
"model": survey,
"data": data,
"page": page,
"unverified": ['budget']
"verification_status": verification_status
}
return jsonify(open_survey)
......@@ -78,7 +83,7 @@ def save_survey() -> Any:
# just a hardcoded year and nren for development for now
nren = db.session.execute(select(NREN).order_by(NREN.id).limit(1)).scalar_one()
year = 1988
year = 1989
survey = db.session.scalar(select(Survey).where(Survey.year == year))
if survey is None:
survey = Survey(year=year, survey={})
......@@ -98,7 +103,7 @@ def save_survey() -> Any:
response.answers = {
"data": save_survey["data"],
"page": save_survey["page"],
"unverified": save_survey["unverified"]
"verification_status": save_survey["verification_status"]
}
db.session.commit()
......
......@@ -2750,6 +2750,11 @@
}
],
"rowTitleWidth": "20%"
},
{
"type": "comment",
"name": "service_comments",
"title": "Comments regarding this section:"
}
],
"title": "Services"
......
......@@ -8,35 +8,43 @@ import './survey.scss';
Serializer.addProperty("itemvalue", "customDescription:text");
Serializer.addProperty("question", "hideCheckboxLabels:boolean");
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
Unverified = "unverified", // a question that has its answered copied from last year
Verified = "verified", // a question for which last years answer was verified
Edited = "edited" // a question for which last years answer was edited
}
function SurveyComponent() {
const [surveyModel, setSurveyModel] = useState<Model>();
const unverifiedQuestions = useRef<string[]>();
const verificationStatus = useRef<Map<string, VerificationStatus>>(new Map());
function setVerifyButton(question: Question, state: string) {
function setVerifyButton(question: Question, state: VerificationStatus) {
const idx = unverifiedQuestions.current?.indexOf(question.name);
if (idx == undefined || idx == -1) {
return;
}
if (state == "verified" || state == "verified!") {
unverifiedQuestions.current?.splice(idx, 1);
}
verificationStatus.current.set(question.name, state);
const btn = document.createElement("button");
btn.type = "button";
btn.className = "dialogBox-btn verify";
btn.className = "sv-action-bar-item verification";
btn.innerHTML = state;
btn.onclick = function() {
question.validate();
setVerifyButton(question, "verified")
if (state == VerificationStatus.Unverified) {
btn.innerHTML = "Verify last years data";
btn.className += " verification-required";
btn.onclick = function() {
question.validate();
setVerifyButton(question, VerificationStatus.Verified)
}
} else {
btn.className += " verification-ok";
}
const selector = '[data-name="' + question.name + '"]';
const header = document.querySelector(selector)!.querySelector('h5')!;
const old = header.querySelector(".verify");
const old = header.querySelector(".verification");
if (old) {
old.replaceWith(btn);
} else {
......@@ -53,7 +61,10 @@ function SurveyComponent() {
const response = await fetch('/api/survey/open');
const json = await response.json();
unverifiedQuestions.current = json["unverified"];
for (const questionName in json["verification_status"]) {
verificationStatus.current.set(questionName, json["verification_status"][questionName]);
}
const survey = new Model(json['model']);
if (json['data'] !== null)
......@@ -65,15 +76,15 @@ function SurveyComponent() {
survey.addNavigationItem({
id: "sv-nav-compendium-complete",
title: "My complete",
title: "Complete",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error: visible may be a ComputedUpdater but the types are not (yet?) aware of this
visible: new ComputedUpdater(() => survey.isLastPage),
action: () => {
let firstValidationError = '';
const verificationValidator = (survey, options) => {
const idx = unverifiedQuestions.current?.indexOf(options.name);
if (idx !== undefined && idx > -1) {
const status = verificationStatus.current.get(options.name);
if (status == VerificationStatus.Unverified) {
if (firstValidationError == '') {
firstValidationError = options.name;
}
......@@ -115,7 +126,7 @@ function SurveyComponent() {
const saveData = {
data: sender.data,
page: 2,
unverified: []
verification_status: Object.fromEntries(verificationStatus.current)
}
xhr.send(JSON.stringify(saveData));
});
......@@ -127,20 +138,26 @@ function SurveyComponent() {
});
survey.onAfterRenderQuestion.add(function(survey, options){
setVerifyButton(options.question, 'unverified');
const status = verificationStatus.current.get(options.question.name);
if (status) {
setVerifyButton(options.question, status);
}
});
survey.onValueChanged.add(function(survey, options) {
setVerifyButton(options.question, 'verified!');
const currentStatus = verificationStatus.current.get(options.question.name);
if (currentStatus == VerificationStatus.New) {
setVerifyButton(options.question, VerificationStatus.Answered);
} else if (currentStatus == VerificationStatus.Unverified) {
setVerifyButton(options.question, VerificationStatus.Edited);
}
});
survey.onUpdateQuestionCssClasses.add(function(_, options) {
if (options.question.hideCheckboxLabels) {
const classes = options.cssClasses;
classes.root += " hidden-checkbox-labels";
}
});
survey.onMatrixAfterCellRender.add((survey, options) => {
......
......@@ -9,3 +9,19 @@
overflow: hidden;
visibility: hidden;
}
.verification {
display: inline-block;
margin-left: 20px;
}
.verification-required {
color: red;
border-style: solid;
border-width: 1px;
}
.sv-action-bar-item.verification.verification-ok:hover {
cursor: auto;
background-color: transparent;
}
\ 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