new appeal progress pattern

This commit is contained in:
2022-07-19 11:54:00 +01:00
parent 58415b82c6
commit ee110bd8a7
6 changed files with 452 additions and 210 deletions
+111 -196
View File
@@ -5,6 +5,7 @@ import { connect } from "react-redux";
import xpath from "xpath";
import { setCurrentSection } from "../../store/appealType/action";
import { FieldsTranslations } from "../elements";
import { getProgressObj } from "../utils";
const BuildProgress = (props) => {
let { t } = useTranslation();
@@ -12,185 +13,23 @@ const BuildProgress = (props) => {
const { locale } = router;
const {
progObj,
titleList,
currentSection,
documentListObj,
formObjXML,
mandatoryFieldsData,
gotoSection,
setCurrentSection,
} = props;
const parser = new DOMParser();
const BuildFormObj = (formObjXML) => {
var doc = parser.parseFromString(formObjXML, "text/xml");
var tabs = xpath.select("//form/tabs/tab[*]", doc);
const formObj = Object.keys(tabs).map((key, index) => {
var sectionXML = xpath.select(
"//tabs/tab[" +
(index + 1) +
"]//rows/row/*/control[not(@parentField)]/../..",
doc
);
return BuildRowObj(sectionXML, titleList[key].value);
});
const progressObj = Object.keys(formObj).map((key, index) => {
let fieldObj = formObj[key].fieldsrowObj;
let rowCount = 0;
typeof props.props.initialValues != "undefined" &&
Object.keys(fieldObj).map((key, index) => {
fieldObj[key].datafieldname in props.props.initialValues &&
props.props.initialValues[
fieldObj[key].datafieldname
] != null &&
rowCount++;
});
return {
"title": titleList[key].value,
rowCount,
"totalFields": formObj[key].fieldsTotal,
"allFieldsComplete": rowCount == formObj[key].fieldsTotal,
};
});
return progressObj;
};
const BuildRowObj = (rowXML, titleList) => {
const rowObj = Object.keys(rowXML).map((key, index) => {
var doc = parser.parseFromString(rowXML[key].outerHTML, "text/xml");
if (_.isEmpty(rowXML[key].innerHTML)) {
("");
} else {
var rows = xpath.select("//label/@description", doc);
var fieldtype = xpath.select("//@classid", doc);
var validation = xpath.select("//@validation", doc);
var datafieldname = xpath.select("//@datafieldname", doc);
var datafieldcontent = xpath.select("//@datafieldcontent", doc);
var parentField = xpath.select("//@parentField", doc);
var parentFieldShowOnValue = xpath.select(
"//@parentFieldShowOnValue",
doc
);
var requiredDocumentValue = xpath.select(
"//@requiredDocumentValue",
doc
);
var requiredDocumentLabel = xpath.select(
"//@requiredDocumentLabel",
doc
);
var hint = xpath.select("//label/@hint", doc);
var dateStart = xpath.select("//@dateStart", doc);
var dateEnd = xpath.select("//@dateEnd", doc);
hint = !_.isEmpty(hint) && hint[0].value;
validation = !_.isEmpty(validation) ? validation[0].value : [];
parentField = !_.isEmpty(parentField) && parentField[0].value;
parentFieldShowOnValue =
!_.isEmpty(parentFieldShowOnValue) &&
parentFieldShowOnValue[0].value;
datafieldcontent =
!_.isEmpty(datafieldcontent) && datafieldcontent[0].value;
requiredDocumentValue =
!_.isEmpty(requiredDocumentValue) &&
requiredDocumentValue[0].value;
requiredDocumentLabel =
!_.isEmpty(requiredDocumentLabel) &&
requiredDocumentLabel[0].value;
dateStart = !_.isEmpty(dateStart) && dateStart[0].value;
dateEnd = !_.isEmpty(dateEnd) && dateEnd[0].value;
const isRequiredField = jsonpath.query(
mandatoryFieldsData,
"$..value[?(@.LogicalName=='" +
datafieldname[0].value +
"')]"
);
if (datafieldname[0].value == "pinswg_fileUpload") {
return {
"fieldType": fieldtype[0].value,
"label": rows[0].value,
"datafieldname": datafieldname[0].value,
"key": key,
"picklistData": props.props.formData.pickListData,
"mandatoryFieldsData": mandatoryFieldsData,
};
} else {
if (typeof isRequiredField[0] != "undefined") {
if (isRequiredField[0].RequiredLevel.Value != "None") {
//console.log(datafieldname[0].value, validation);
return {
"fieldType": fieldtype[0].value,
"label": rows[0].value,
"datafieldname": datafieldname[0].value,
"datafieldcontent": datafieldcontent,
"parentField": parentField,
"parentFieldShowOnValue":
parentFieldShowOnValue,
"key": key,
"picklistData":
props.props.formData.pickListData,
"mandatoryFieldsData": mandatoryFieldsData,
"hint": hint,
"requiredDocumentLabel": requiredDocumentLabel,
"requiredDocumentValue": requiredDocumentValue,
"validation": validation,
"dateStart": dateStart,
"dateEnd": dateEnd,
"setDocumentsList":
props.props.setDocumentsList,
"documentList":
props.props.appealType.documentList,
};
} else {
return null;
}
} else {
return null;
}
}
}
});
rowObj = rowObj.filter(function (el) {
return el != null;
});
const filterUnwanted = (rowObj) => {
const required = rowObj.filter((el) => {
return !_.isEmpty(el.validation);
});
return required;
};
return {
"title": titleList,
"validationFieldsTotal": filterUnwanted(rowObj).length,
"fieldsTotal": rowObj.length,
"fieldsrowObj": rowObj,
};
};
const progObj = BuildFormObj(formObjXML);
// const progObj = getProgressObj(
// formObjXML,
// titleList,
// mandatoryFieldsData,
// props
// );
return (
<>
@@ -205,9 +44,82 @@ const BuildProgress = (props) => {
{props.props.appealType.caseReference.ticketnumber}
</span>
</h2>
<hr className="govuk-section-break govuk-section-break--m govuk-section-break--visible" />
<ol className="govuk-list" id="progress-list">
{/* <hr className="govuk-section-break govuk-section-break--m govuk-section-break--visible" /> */}
<div
id="step-by-step-navigation"
data-module="gemstepnav"
className="app-step-nav app-step-nav--active"
data-id="e01e924b-9c7c-4c71-8241-66a575c2f61f"
data-show-text="show"
data-hide-text="hide"
data-show-all-text="Show all"
data-hide-all-text="Hide all"
>
<ol className="app-step-nav__steps">
{Object.keys(progObj).map((key, index) => (
<li
key={key}
className={
"app-step-nav__step js-step app-step-nav__step--active" +
(progObj[index].allFieldsComplete
? " sectionComplete"
: " sectionIncomplete")
}
aria-current="step"
data-show=""
id="check-youre-allowed-to-drive"
>
<div
className="app-step-nav__header js-toggle-panel "
data-position={index}
>
<h3 className="app-step-nav__title ">
<span className="app-step-nav__circle app-step-nav__circle--number">
<span className="app-step-nav__circle-inner">
<span className="app-step-nav__circle-background">
<span className="app-step-nav__circle-step-label govuk-visually-hidden">
Step
</span>{" "}
{index + 1}
<span
className="app-step-nav__circle-step-colon govuk-visually-hidden"
aria-hidden="true"
>
:
</span>
</span>
</span>
</span>
<span className="js-step-title">
<a
href="#"
onClick={() => {
gotoSection(
parseInt(key) + 1
);
}}
className="app-step-nav__button app-step-nav__button--title js-step-title-button"
aria-expanded="false"
aria-controls="step-panel-check-youre-allowed-to-drive-1"
>
<span className="js-step-title-text govuk-!-font-size-16">
{FieldsTranslations(
progObj[index].title
)}
</span>
</a>
</span>
</h3>
</div>
</li>
))}
</ol>
</div>
{/* <ol className="govuk-list" id="progress-list">
<ul className="govuk-list ">
<li className="at-nav__page">
<ol className="govuk-list">
@@ -222,37 +134,40 @@ const BuildProgress = (props) => {
</li>
) : (
<li key={key}>
{props.props.appealType
.formComplete == "true" ||
parseInt(key) + 1 <
currentSection ||
progObj[index].allFieldsComplete ==
true ? (
<a
className="govuk-link"
href="#"
onClick={() => {
gotoSection(
parseInt(key) + 1
);
}}
>
{FieldsTranslations(
progObj[index].title
)}
</a>
) : (
FieldsTranslations(
{" "}
<span
title={
progObj[index].title +
` complete`
}
className={
progObj[index]
.allFieldsComplete ==
true
? `sectionCompleteTick`
: `sectionIncomplete`
}
></span>
<a
className="govuk-link"
href="#"
onClick={() => {
gotoSection(
parseInt(key) + 1
);
}}
>
{FieldsTranslations(
progObj[index].title
)
)}
)}
</a>
</li>
)
)}
</ol>
</li>
</ul>
</ol>
</ol> */}
</nav>
{Object.keys(documentListObj).length > 0 && (
+72 -14
View File
@@ -1,5 +1,5 @@
import Link from "next/link";
import _, { has } from "lodash";
import _, { has, last } from "lodash";
import { useRouter } from "next/router";
import useTranslation from "next-translate/useTranslation";
import { useState, useEffect } from "react";
@@ -12,8 +12,9 @@ import {
setCurrentSection,
setDocumentsList,
setFilesForAppeal,
setNewAppealProgress,
} from "../../store/appealType/action";
import { getFormCollectionByID } from "../utils";
import { getFormCollectionByID, getProgressObj } from "../utils";
import { updateCase, patchCase, uploadFiles } from "../../actions";
import { FieldsTranslations } from "../elements";
@@ -21,9 +22,30 @@ import jsonpath from "jsonpath";
import BuildProgress from "./buildprogress";
let BuildSection = (props) => {
// useEffect(() => {
// window.scrollTo(0, 0);
// });
const [currentSectionSelected, setCurrentSectionSelected] = useState(1);
const [pickupWhereLeftOff, setPickupWhereLeftOff] = useState(true);
useEffect(() => {
progObj = getProgressObj(
formXML,
titleList,
mandatoryFieldsData,
props
);
// const lastIndex = progObj
// .map((whichIsLast) => whichIsLast.allFieldsComplete == true)
// .lastIndexOf(true);
// setCurrentSection(currentSectionSelected + 1);
// pickupWhereLeftOff == true && setCurrentSection(lastIndex + 1),
// setPickupWhereLeftOff(false);
// // lastIndex != currentSectionSelected
// // ? (setCurrentSectionSelected(lastIndex),
// // setPickupWhereLeftOff(true))
// // : setPickupWhereLeftOff(false);
});
let { t } = useTranslation();
@@ -68,6 +90,17 @@ let BuildSection = (props) => {
doc
);
const progObj = getProgressObj(
formXML,
titleList,
mandatoryFieldsData,
props
);
const lastIndex = progObj
.map((whichIsLast) => whichIsLast.allFieldsComplete == true)
.lastIndexOf(true);
const handleParam = (setValue) => (e) => setValue(e.target.value);
const uploadAppealFiles = (values) => {
@@ -76,7 +109,7 @@ let BuildSection = (props) => {
return _.includes(key, "pinswg_fileUpload");
});
console.log(fileListObj);
//console.log(fileListObj);
var dataObj = values;
@@ -85,7 +118,7 @@ let BuildSection = (props) => {
}
uploadFiles(dataObj, fileListObj).then((data) => {
console.log("hello", data);
//console.log("hello", data);
return data;
});
@@ -96,6 +129,9 @@ let BuildSection = (props) => {
let updateBody = values || {};
uploadAppealFiles(values);
props.setNewAppealProgress(
getProgressObj(formXML, titleList, mandatoryFieldsData, props)
);
let appTypeCollection = getFormCollectionByID(
props.appealType.appealTypeID
@@ -142,13 +178,12 @@ let BuildSection = (props) => {
};
const onHandleSubmit = (values) => {
if (currentSection == sectionCount) {
let valuesObj = values || {};
//if (currentSection == sectionCount) {
let valuesObj = values || {};
delete valuesObj["_pinswg_appellant_value"];
updateCaseProgress(valuesObj);
}
delete valuesObj["_pinswg_appellant_value"];
console.log("has errors:", props.invalid);
props.invalid == false && updateCaseProgress(valuesObj);
setCurrentSection(currentSection + 1);
};
@@ -250,7 +285,22 @@ let BuildSection = (props) => {
type="submit"
className="govuk-button"
data-module="govuk-button"
onClick={() => getErrors()}
onClick={() => {
getErrors();
let valuesObj = _.has(
props1.props.form[props1.form],
"values"
)
? props.props.form[props.form].values
: {};
//console.log("valuesobj:", valuesObj);
delete valuesObj["_pinswg_appellant_value"];
//console.log("on save:", valuesObj);
updateCaseProgress(valuesObj);
}}
>
{t("common:continue-button")}
</button>
@@ -286,7 +336,11 @@ let BuildSection = (props) => {
</div>
<div className="govuk-grid-column-one-third">
<div className="at-nav-container">
{/* <span>
Last section is {lastIndex} - {currentSection}
</span> */}
<BuildProgress
progObj={progObj}
props={props}
titleList={titleList}
documentListObj={documentListObj}
@@ -294,6 +348,7 @@ let BuildSection = (props) => {
mandatoryFieldsData={mandatoryFieldsData}
currentSection={currentSection}
initialValues={props.initialValues}
setCurrentSection={setCurrentSection}
/>
<hr className="govuk-section-break govuk-section-break--m govuk-section-break--visible" />
@@ -349,6 +404,9 @@ const mapDispatchToProps = (dispatch) => {
setFilesForAppeal: (blobList) => {
dispatch(setFilesForAppeal(blobList));
},
setNewAppealProgress: (progressObj) => {
dispatch(setNewAppealProgress(progressObj));
},
};
};
+177
View File
@@ -6,6 +6,8 @@ import {
getBasicPartSavedDetails,
} from "../../actions";
import xpath from "xpath";
/*
* Get the lookup collection by the appeal type entity
* @param String formtype - string from appeal entity name
@@ -164,3 +166,178 @@ export const getSearchDetailsPaged = (searchResultsObj) => {
// origin: protocol + "//" + host,
// };
// };
export const getProgressObj = (
formObjXML,
titleList,
mandatoryFieldsData,
props
) => {
const parser = new DOMParser();
const BuildFormObj = (formObjXML) => {
var doc = parser.parseFromString(formObjXML, "text/xml");
var tabs = xpath.select("//form/tabs/tab[*]", doc);
const formObj = Object.keys(tabs).map((key, index) => {
var sectionXML = xpath.select(
"//tabs/tab[" +
(index + 1) +
"]//rows/row/*/control[not(@parentField)]/../..",
doc
);
return BuildRowObj(sectionXML, titleList[key].value);
});
const progressObj = Object.keys(formObj).map((key, index) => {
let fieldObj = formObj[key].fieldsrowObj;
let rowCount = 0;
!props.dirty &&
typeof props.initialValues != "undefined" &&
Object.keys(fieldObj).map((key, index) => {
fieldObj[key].datafieldname in props.initialValues &&
props.initialValues[fieldObj[key].datafieldname] !=
null &&
rowCount++;
});
props.dirty &&
Object.keys(fieldObj).map((key, index) => {
fieldObj[key].datafieldname in
props.props.form["appealForm"].values &&
props.props.form["appealForm"].values[
fieldObj[key].datafieldname
] != null &&
rowCount++;
});
return {
"title": titleList[key].value,
rowCount,
"totalFields": formObj[key].fieldsTotal,
"allFieldsComplete": rowCount == formObj[key].fieldsTotal,
};
});
return progressObj;
};
const BuildRowObj = (rowXML, titleList) => {
const rowObj = Object.keys(rowXML).map((key, index) => {
var doc = parser.parseFromString(rowXML[key].outerHTML, "text/xml");
if (_.isEmpty(rowXML[key].innerHTML)) {
("");
} else {
var rows = xpath.select("//label/@description", doc);
var fieldtype = xpath.select("//@classid", doc);
var validation = xpath.select("//@validation", doc);
var datafieldname = xpath.select("//@datafieldname", doc);
var datafieldcontent = xpath.select("//@datafieldcontent", doc);
var parentField = xpath.select("//@parentField", doc);
var parentFieldShowOnValue = xpath.select(
"//@parentFieldShowOnValue",
doc
);
var requiredDocumentValue = xpath.select(
"//@requiredDocumentValue",
doc
);
var requiredDocumentLabel = xpath.select(
"//@requiredDocumentLabel",
doc
);
var hint = xpath.select("//label/@hint", doc);
var dateStart = xpath.select("//@dateStart", doc);
var dateEnd = xpath.select("//@dateEnd", doc);
hint = !_.isEmpty(hint) && hint[0].value;
validation = !_.isEmpty(validation) ? validation[0].value : [];
parentField = !_.isEmpty(parentField) && parentField[0].value;
parentFieldShowOnValue =
!_.isEmpty(parentFieldShowOnValue) &&
parentFieldShowOnValue[0].value;
datafieldcontent =
!_.isEmpty(datafieldcontent) && datafieldcontent[0].value;
requiredDocumentValue =
!_.isEmpty(requiredDocumentValue) &&
requiredDocumentValue[0].value;
requiredDocumentLabel =
!_.isEmpty(requiredDocumentLabel) &&
requiredDocumentLabel[0].value;
dateStart = !_.isEmpty(dateStart) && dateStart[0].value;
dateEnd = !_.isEmpty(dateEnd) && dateEnd[0].value;
const isRequiredField = jsonpath.query(
mandatoryFieldsData,
"$..value[?(@.LogicalName=='" +
datafieldname[0].value +
"')]"
);
if (datafieldname[0].value == "pinswg_fileUpload") {
return {
"fieldType": fieldtype[0].value,
"label": rows[0].value,
"datafieldname": datafieldname[0].value,
"key": key,
"picklistData": props.props.formData.pickListData,
"mandatoryFieldsData": mandatoryFieldsData,
};
} else {
if (typeof isRequiredField[0] != "undefined") {
if (isRequiredField[0].RequiredLevel.Value != "None") {
//console.log(datafieldname[0].value, validation);
return {
"fieldType": fieldtype[0].value,
"label": rows[0].value,
"datafieldname": datafieldname[0].value,
"datafieldcontent": datafieldcontent,
"validation": validation,
};
} else {
return null;
}
} else {
return null;
}
}
}
});
rowObj = rowObj.filter(function (el) {
return el != null;
});
const filterUnwanted = (rowObj) => {
const required = rowObj.filter((el) => {
return !_.isEmpty(el.validation);
});
return required;
};
return {
"title": titleList,
"validationFieldsTotal": filterUnwanted(rowObj).length,
"fieldsTotal": rowObj.length,
"fieldsrowObj": rowObj,
};
};
const progObj = BuildFormObj(formObjXML);
//console.log(progObj);
return progObj;
};
+8
View File
@@ -10,6 +10,7 @@ export const appealTypeDataActionTypes = {
SETFORMCOMPLETE: "SETFORMCOMPLETE",
SETDOCUMENTLIST: "SETDOCUMENTLIST",
SETFILELIST: "SETFILELIST",
SETNEWAPPEALPROGRESS: "SETNEWAPPEALPROGRESS",
};
export const getAppealTypeObj = () => (dispatch) => {
@@ -78,3 +79,10 @@ export const setFilesForAppeal = (fileList) => (dispatch) => {
fileList: fileList,
});
};
export const setNewAppealProgress = (progress) => (dispatch) => {
return dispatch({
type: appealTypeDataActionTypes.SETNEWAPPEALPROGRESS,
progress: progress,
});
};
+6
View File
@@ -10,6 +10,7 @@ const appealTypeDataInitialState = {
formComplete: "false",
documentList: {},
fileList: {},
progress: [],
};
export default function reducer(state = appealTypeDataInitialState, action) {
@@ -59,6 +60,11 @@ export default function reducer(state = appealTypeDataInitialState, action) {
...state,
fileList: action.fileList,
};
case appealTypeDataActionTypes.SETNEWAPPEALPROGRESS:
return {
...state,
progress: action.progress,
};
default:
return state;
}
+78
View File
@@ -40,6 +40,7 @@ h2,
h3,
h4,
h5,
.app-step-nav__circle-background,
a {
font-family: Arial, Helvetica, "Nimbus Sans L", sans-serif;
}
@@ -770,6 +771,82 @@ textarea,
margin-bottom: 0px;
}
.at-nav {
.sectionCompleteTick {
display:inline-block;
width: 16px;
height:16px;
background: $darkgrey;
border-radius:50%;
-ms-transform: rotate(45deg); /* IE 9 */
-webkit-transform: rotate(45deg); /* Chrome, Safari, Opera */
transform: rotate(45deg);
margin-left: -20px;
margin-right: 5px;
}
.sectionCompleteTick:before{
content: "";
position: absolute;
width: 3px;
height: 9px;
background-color: #fff;
left: 8px;
top: 3px;
}
.sectionCompleteTick:after{
content: "";
position: absolute;
width: 3px;
height: 3px;
background-color: #fff;
left: 5px;
top: 9px;
}
.app-step-nav__step {
position: relative;
padding-left: 45px;
list-style: none;
}
*, .govuk-body, .govuk-body-xs, .govuk-body-s, .govuk-body-m, .govuk-footer, .govuk-heading-xl, .govuk-heading-l, .govuk-heading-m, .govuk-heading-s, .govuk-header-l, .govuk-header-m, .govuk-header__link, .govuk-footer__link, .govuk-link, .govuk-button, .govuk-label, .govuk-select, .govuk-radios__item, .govuk-breadcrumbs__link, .govuk-fieldset__legend--s, .govuk-input, .govuk-textarea, .govuk-panel, .govuk-panel__title, .govuk-warning-text__text, .govuk-hint, .app-cookie-banner, .govuk-error-message.govuk-form-group--error, h1, h2, h3, h4, h5, a {
font-family: Arial, Helvetica, "Nimbus Sans L", sans-serif;
}
user agent stylesheet
li {
display: list-item;
text-align: -webkit-match-parent;
}
user agent stylesheet
ol {
list-style-type: decimal;
}
.app-step-nav__step--active:last-child:before, .app-step-nav__step--active .app-step-nav__circle--number, .app-step-nav__step--active:after, .app-step-nav__step--active .app-step-nav__help:after
{
border-color: $lightgrey !important;
}
.app-step-nav__circle--number{
border-color: $lightgrey !important;
}
.app-step-nav__circle-background{
color:$lightgrey;
}
.sectionComplete{
.app-step-nav__circle {
background-color: $lightgrey;
}
.app-step-nav__circle-background{
color:$white;
text-shadow: none;
}
}
}
.form-inline-label {
.inlineFieldset {
display: flex;
@@ -864,6 +941,7 @@ textarea,
}
}
.progress-save{
padding: 10px 15px !important;
font-size: 16px;