From ee110bd8a7aa4a5a17dec9bf9fee813f5dd8e8de Mon Sep 17 00:00:00 2001 From: rdbsolutions Date: Tue, 19 Jul 2022 11:54:00 +0100 Subject: [PATCH] new appeal progress pattern --- components/newappeal/buildprogress.js | 307 +++++++++---------------- components/newappeal/buildsection.js | 86 +++++-- components/utils/index.js | 177 ++++++++++++++ store/appealType/action.js | 8 + store/appealType/reducer.js | 6 + styles/sass/welshgov/_application.scss | 78 +++++++ 6 files changed, 452 insertions(+), 210 deletions(-) diff --git a/components/newappeal/buildprogress.js b/components/newappeal/buildprogress.js index 7b752d01..38e6d3b1 100644 --- a/components/newappeal/buildprogress.js +++ b/components/newappeal/buildprogress.js @@ -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} -
-
    + {/*
    */} + + + + {/*
      -
    +
*/} {Object.keys(documentListObj).length > 0 && ( diff --git a/components/newappeal/buildsection.js b/components/newappeal/buildsection.js index 42aa3b36..638c1b65 100644 --- a/components/newappeal/buildsection.js +++ b/components/newappeal/buildsection.js @@ -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")} @@ -286,7 +336,11 @@ let BuildSection = (props) => {
+ {/* + Last section is {lastIndex} - {currentSection} + */} { mandatoryFieldsData={mandatoryFieldsData} currentSection={currentSection} initialValues={props.initialValues} + setCurrentSection={setCurrentSection} />
@@ -349,6 +404,9 @@ const mapDispatchToProps = (dispatch) => { setFilesForAppeal: (blobList) => { dispatch(setFilesForAppeal(blobList)); }, + setNewAppealProgress: (progressObj) => { + dispatch(setNewAppealProgress(progressObj)); + }, }; }; diff --git a/components/utils/index.js b/components/utils/index.js index 32ac3c10..bb2004cb 100644 --- a/components/utils/index.js +++ b/components/utils/index.js @@ -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; +}; diff --git a/store/appealType/action.js b/store/appealType/action.js index b93b21e5..1f9a6037 100644 --- a/store/appealType/action.js +++ b/store/appealType/action.js @@ -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, + }); +}; diff --git a/store/appealType/reducer.js b/store/appealType/reducer.js index 75333e6d..f6eca85b 100644 --- a/store/appealType/reducer.js +++ b/store/appealType/reducer.js @@ -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; } diff --git a/styles/sass/welshgov/_application.scss b/styles/sass/welshgov/_application.scss index 902d81d4..bea42056 100644 --- a/styles/sass/welshgov/_application.scss +++ b/styles/sass/welshgov/_application.scss @@ -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;