Files
Robert Bond ffcccf8981 Merged PR 2240: refactor(newappeal): simplify nested prop boundaries (Slice 7)
refactor(newappeal): simplify nested prop boundaries (Slice 7)

Related work items: #22588
2026-04-13 12:25:45 +00:00

707 lines
26 KiB
JavaScript

import _ from "lodash";
import useTranslation from "next-translate/useTranslation";
import { useRouter } from "next/router";
import { useState } from "react";
import { connect } from "react-redux";
import { formValueSelector, reduxForm } from "redux-form";
import { mergeWithExistingFilesList } from "../../lib/newappeal/fileListHelpers";
import {
uploadAppealFilesEffect,
sendPartialSaveEmailEffect
} from "../../lib/newappeal/journeyEffects";
import {
normalizeYesNoBooleans,
removeNullKeys,
stripInternalKeys
} from "../../lib/newappeal/payloadCleanup";
import {
setCurrentSection,
setDocumentsList,
setFilesForAppeal,
setNewAppealProgress,
setFileCount
} from "../../store/appealType/action";
import { getFormCollectionByID, getProgressObj, updateLinks } from "../utils";
import BuildRow from "./buildrow";
import {
parseXml,
selectAllTabTitleDescriptions,
selectCurrentSectionRows,
selectCurrentSectionTitleDescriptions,
selectErrorFieldLabelDescription,
selectFormTabs
} from "../../lib/newappeal/formDerivation";
import { FieldsTranslations } from "../elements";
import BuildProgress from "./buildprogress";
import ErrorSummary from "./buildSection/ErrorSummary";
import PrimaryActionButtons from "./buildSection/PrimaryActionButtons";
import SaveStatusIndicator from "./buildSection/SaveStatusIndicator";
import SectionHeader from "./buildSection/SectionHeader";
import SidebarProgressPanel from "./buildSection/SidebarProgressPanel";
let BuildSection = (props) => {
const [currentSectionSelected, setCurrentSectionSelected] = useState(1);
const [pickupWhereLeftOff, setPickupWhereLeftOff] = useState(true);
const [savingStatus, setSavingStatus] = useState(false);
const [allFilesUploaded, setAllFilesuploaded] = useState(false);
const [showCompletedUploadFiles, setShowCompletedUploadFiles] =
useState(false);
const [completedUploadFiles, setCompletedUploadFiles] = useState(false);
const [uploadCount, setUploadCount] = useState(0);
const [completedUploadFilesCount, setCompletedUploadFilesCount] =
useState(0);
let { t } = useTranslation();
const router = useRouter();
const { locale } = router;
const {
formXML,
sectionCount,
onSubmit,
handleSubmit,
load,
pristine,
reset,
formTitle,
setCurrentSection,
refno,
gotoSection,
mandatoryFieldsData
} = props;
const legacyProps = props.props;
const legacyAccountDetails = legacyProps.accountDetails;
const legacyFormState = legacyProps.form;
const legacyAppealType = legacyProps.appealType;
const legacyUrl = legacyProps.url;
const documentListObj = props.appealType.documentList;
const currentSection = props.appealType.currentSection;
var doc = parseXml(props.formXML);
var titles = selectCurrentSectionTitleDescriptions(doc, currentSection);
var rowXML = selectCurrentSectionRows(doc, currentSection);
var formObjXML = selectFormTabs(doc);
var titleList = selectAllTabTitleDescriptions(doc);
const progObj = getProgressObj(
formXML,
titleList,
mandatoryFieldsData,
props
);
const isProgressComplete = (progObj) => {
let progressCount = 0;
for (let key in progObj) {
progObj[key].allFieldsComplete === true && progressCount++;
}
return progObj.length == progressCount;
};
const lastIndex = progObj
.map((whichIsLast) => whichIsLast.allFieldsComplete == true)
.lastIndexOf(true);
const handleParam = (setValue) => (e) => setValue(e.target.value);
const uploadAppealFiles = async (values) => {
// get filelists from values object
let fileListObj = _.filter(values, function (v, key) {
return _.includes(key, "pinswg_fileUpload");
});
fileListObj = [];
//console.log(fileListObj);
// console.log(
// "\n////////////////////////\n upload files:",
// props.props.accountDetails.containerID
// );
var dataObj = values;
// for (let key in dataObj) {
// _.includes(key, "pinswg_fileUpload") == true && delete dataObj[key];
// }
await uploadAppealFilesEffect(
dataObj,
fileListObj,
legacyAccountDetails.containerID,
legacyAppealType.caseReference.ticketnumber
).then((data) => {
//console.log("$1", data);
setCompletedUploadFiles(true);
return data;
});
};
const updateCaseProgress = async (
values,
sendSavedEmail,
useSaveStatus
) => {
let incidentId = props.appealType.caseReference.incidentid;
let updateBody = values || {};
let buildAppealFilesArray = [];
//console.log("attached docs: - ", buildAppealFilesArray);
values = updateLinks(values);
let filesUploadObj = Object.keys(values)
.filter(function (k) {
return k.indexOf("pinswg_fileUpload") == 0;
})
.reduce(function (newData, k) {
newData[k] = values[k];
return newData;
}, {});
//console.log(filesUploadObj);
for (let key in filesUploadObj) {
for (let j in filesUploadObj[key]) {
typeof filesUploadObj[key][j].name != "undefined" &&
buildAppealFilesArray.push({
"name": filesUploadObj[key][j].name,
"size": filesUploadObj[key][j].size
});
}
}
//console.log(buildAppealFilesArray);
buildAppealFilesArray = mergeWithExistingFilesList(
buildAppealFilesArray,
values
);
Object.assign(values, { "filesList": buildAppealFilesArray });
setSavingStatus(useSaveStatus);
//not sure we need this here if it does it on drop of file
uploadAppealFiles(values);
// console.log(
// "\n////////////////////////\n appeal pdf payload",
// values,
// props.props.accountDetails.containerID,
// props.appealType.caseReference.ticketnumber,
// props.appealType,
// "\n////////////////////////\n"
// );
// let pdfObj = values;
// Object.assign(pdfObj, {
// "containerID": props.props.accountDetails.containerID,
// "casefolderID": props.appealType.caseReference.ticketnumber,
// });
// generateAppealPDF(
// pdfObj,
// props.props.accountDetails.containerID,
// props.appealType.caseReference.ticketnumber,
// router.query.appealtypes,
// props.appealType.fileList
// ),
props.setNewAppealProgress(
getProgressObj(formXML, titleList, mandatoryFieldsData, props)
);
let appTypeCollection = getFormCollectionByID(
props.appealType.appealTypeID
);
let updateBindAppealTypeToIncident =
appTypeCollection.NavigationProperty;
Object.assign(updateBody, {
"pinswg_appealcasetype": props.appealType.appealTypeID,
"pinswg_Appellant@odata.bind":
"/contacts(" + legacyAccountDetails.loggedinUserId + ")",
"pinswg_name": props.appealType.caseReference.ticketnumber,
[updateBindAppealTypeToIncident + "@odata.bind"]:
"/incidents(" + incidentId + ")"
});
updateBody = normalizeYesNoBooleans(updateBody);
updateBody = removeNullKeys(updateBody);
updateBody = stripInternalKeys(updateBody);
//console.log(updateBody);
let updateFormCollection = appTypeCollection.LogicalCollectionName;
let primaryAttribute = appTypeCollection.PrimaryIdAttribute;
const reference = "PEDW-PARTIAL";
const templateId = "021b0a7b-df00-41f1-b94e-c269bee98c75";
const templateIdCY = "f3c4a56b-bfb8-4d39-97dd-888df3062b0a";
const emailAddress = legacyAccountDetails.loggedinUserEmail;
const personalisation = {
"caseReference": props.appealType.caseReference.ticketnumber,
"emailAddress": legacyAccountDetails.loggedinUserEmail,
"returnLink":
legacyUrl +
(router.locale != "en" ? "/cy/fymhorth/" : "/myportal/") +
appTypeCollection.UrlName +
"?lpa=" +
props.appealType.appealLPA +
"&apt=" +
appTypeCollection.appealTypeID +
"&casereference=" +
props.appealType.caseReference.ticketnumber +
"&inid=" +
props.appealType.caseReference.incidentid,
"linkExpiry": 10 * 60
};
// console.log(
// "/////////////////////////////////",
// "returnLink:",
// props.props.url +
// (router.locale != "en" ? "/cy/fymhorth/" : "/myportal/") +
// appTypeCollection.UrlName +
// "?lpa=" +
// props.appealType.appealLPA +
// "&apt=" +
// appTypeCollection.appealTypeID +
// "&casereference=" +
// props.appealType.caseReference.ticketnumber +
// "&inid=" +
// props.appealType.caseReference.incidentid,
// "/////////////////////////////////"
// );
sendSavedEmail == true &&
sendPartialSaveEmailEffect(
router.locale != "en" ? templateIdCY : templateId,
emailAddress,
personalisation,
reference
);
useSaveStatus &&
router.replace(
router.locale != "en"
? "/" + router.locale + "/fymhorth"
: "/myportal"
);
};
const onHandleSubmit = (values) => {
//if (currentSection == sectionCount) {
let valuesObj = values || {};
let buildAppealFilesArray = [];
let filesUploadObj = Object.keys(values)
.filter(function (k) {
return k.indexOf("pinswg_fileUpload") == 0;
})
.reduce(function (newData, k) {
newData[k] = values[k];
return newData;
}, {});
//console.log(filesUploadObj);
for (let key in filesUploadObj) {
for (let j in filesUploadObj[key]) {
buildAppealFilesArray.push({
"name": filesUploadObj[key][j].name,
"size": filesUploadObj[key][j].size
});
}
}
//console.log(buildAppealFilesArray);
setFilesForAppeal(buildAppealFilesArray);
// Object.assign(values, { "filesList": buildAppealFilesArray });
// Function to parse a specific key (e.g., 'price') in an array of objects
const parseFloatForKeyInObject = (obj, key) => {
// Check if the object has the key and the value can be parsed as a float
if (
obj.hasOwnProperty(key) &&
typeof obj[key] === "string" &&
!isNaN(obj[key].trim())
) {
// Parse the value as a float and update the object
return { ...obj, [key]: parseFloat(obj[key]) };
}
// If the key doesn't exist or value can't be parsed, return the original object
return obj;
};
valuesObj = parseFloatForKeyInObject(
valuesObj,
"pinswg_areaofsiteinhectaresdec"
);
delete valuesObj["_pinswg_appellant_value"];
//console.log("has errors:", props.invalid);
props.invalid == false &&
updateCaseProgress(valuesObj, false, false).then((data) => {
console.log(data);
setCurrentSection(currentSection + 1);
});
};
const [hasErrors, setHasErrors] = useState("");
const getErrors = () => {
let errorsobj = legacyFormState["appealForm"];
//setHasErrors(errorsobj.hasOwnProperty("syncErrors"));
window.scrollTo(0, 0);
};
const getErrorItems = () => {
let errorsobj = _.keys(
_.get(props, "props.form.appealForm.syncErrors", {})
);
const getErrorLabel = (whichField) => {
var doc = parseXml(props.formXML);
var errorFieldLabel = selectErrorFieldLabelDescription(
doc,
whichField
);
return errorFieldLabel[0].value;
};
let errorItems = [];
for (let i = 0; i < errorsobj.length; ++i) {
errorItems.push({
"field": errorsobj[i],
"label": getErrorLabel(errorsobj[i])
});
}
return errorItems;
};
const hasUploadFiles = () => {
const formArr = legacyFormState["appealForm"].values;
const prefix = "pinswg_fileUpload";
const hasFiles = Object.keys(formArr).some((key) =>
key.startsWith(prefix)
);
return hasFiles;
};
return (
<div className="govuk-grid-row">
<div className="govuk-grid-column-two-thirds wgForm ">
<SectionHeader title={FieldsTranslations(titles[0].value)} />
<form onSubmit={handleSubmit(onHandleSubmit)}>
<ErrorSummary
hasErrors={hasErrors == true}
errorItems={getErrorItems()}
/>
<BuildRow
rowXML={rowXML}
whichSection={props.whichSection}
sectionCount={props.sectionCount}
onSubmit={onSubmit}
mandatoryFieldsData={mandatoryFieldsData}
props={props}
allFilesUploaded={allFilesUploaded}
setAllFilesuploaded={setAllFilesuploaded}
setFileCount={setFileCount}
setUploadCount={setUploadCount}
uploadCount={uploadCount}
completedUploadFilesCount={completedUploadFilesCount}
setCompletedUploadFilesCount={
setCompletedUploadFilesCount
}
/>
<PrimaryActionButtons>
{props.sectionCount != currentSection ? (
<>
<button
type="submit"
className="govuk-button"
data-module="govuk-button"
onClick={() => {
getErrors();
let valuesObj = _.has(
legacyFormState[props.form],
"values"
)
? legacyFormState[props.form].values
: {};
//console.log("valuesobj:", valuesObj);
delete valuesObj[
"_pinswg_appellant_value"
];
//console.log("on save:", valuesObj);
updateCaseProgress(
valuesObj,
false,
false
);
// currentSection == 1 &&
// setCurrentSection(1);
}}
>
{t("common:continue-button")}
</button>
{currentSection > 1 &&
(savingStatus ? (
<SaveStatusIndicator
text={
router.locale == "cy"
? "Nôl data"
: "Saving data"
}
/>
) : (
<button
className="govuk-button progress-save "
onClick={() => {
let valuesObj =
legacyFormState[props.form]
.values || {};
// console.log(
// "valuesobj:",
// valuesObj
// );
delete valuesObj[
"_pinswg_appellant_value"
];
// console.log("on save:", valuesObj);
updateCaseProgress(
valuesObj,
true,
true
);
}}
>
{t("common:save-exit-button")}
</button>
))}
{/* <span
onClick={() =>
setCurrentSection(sectionCount + 1)
}
>
goto check
</span> */}
</>
) : (
""
)}
{props.sectionCount == currentSection ? (
<>
<div>
{showCompletedUploadFiles
? "UPlodeding, pleas ewait "
: ""}
</div>
<button
disabled={!isProgressComplete(progObj)}
type="submit"
className="govuk-button"
data-module="govuk-button"
>
{t("common:submit-button")}{" "}
</button>
{savingStatus ? (
<SaveStatusIndicator
text={
router.locale == "cy"
? "Nôl data"
: "Saving data"
}
/>
) : (
<button
className="govuk-button progress-save "
onClick={() => {
let valuesObj =
legacyFormState[props.form]
.values || {};
// console.log(
// "valuesobj:",
// valuesObj
// );
delete valuesObj[
"_pinswg_appellant_value"
];
//console.log("on save:", valuesObj);
updateCaseProgress(
valuesObj,
true,
true
);
}}
>
{t("common:save-exit-button")}
</button>
)}
</>
) : (
""
)}
{/* {currentSection > 1 ? (
<a
className="govuk-link"
href="#"
onClick={() =>
setCurrentSection(currentSection - 1)
}
>
{t("common:back-link")}
</a>
) : (
""
)} */}
</PrimaryActionButtons>
</form>
</div>
<SidebarProgressPanel>
{/* <span>
Last section is {lastIndex} - {currentSection}
</span> */}
<BuildProgress
progObj={progObj}
props={props}
titleList={titleList}
documentListObj={documentListObj}
formObjXML={formXML}
mandatoryFieldsData={mandatoryFieldsData}
currentSection={currentSection}
initialValues={props.initialValues}
setCurrentSection={setCurrentSection}
/>
</SidebarProgressPanel>
</div>
);
};
const mapStateToProps = (state, ownProps) => {
return ownProps.props.hasOwnProperty("initialValues")
? {
search: state.search,
searchResultsObj: state.searchResultsObj,
formData: state.formData,
appealType: state.appealType,
initialValues: state.appealType.caseReference.caseDetails,
currentView: state.currentView
}
: {
search: state.search,
searchResultsObj: state.searchResultsObj,
formData: state.formData,
appealType: state.appealType,
currentView: state.currentView
//form: state.form,
};
};
const mapDispatchToProps = (dispatch) => {
return {
setCurrentSection: (currentSection) => {
dispatch(setCurrentSection(currentSection));
},
gotoSection: (thisSection) => {
dispatch(setCurrentSection(thisSection));
},
setDocumentsList: (documentList) => {
dispatch(setDocumentsList(documentList));
},
setFilesForAppeal: (blobList) => {
dispatch(setFilesForAppeal(blobList));
},
setNewAppealProgress: (progressObj) => {
dispatch(setNewAppealProgress(progressObj));
},
setFileCount: (fileCount) => {
dispatch(setFileCount(fileCount));
}
};
};
const selector = formValueSelector("appealForm"); // <-- same as form name
const validate = (values, props) => {
const errors = {};
const strippedHtml = (htmlStr) => {
return htmlStr.replace(/(<([^>]+)>)/gi, "").trim();
};
const locale = props.currentView.locale;
if (values.hasOwnProperty("pinswg_attachsoc")) {
if (values.pinswg_attachsoc == "false") {
if (values.hasOwnProperty("pinswg_statementofcase")) {
if (strippedHtml(values.pinswg_statementofcase).length == 0)
errors.pinswg_statementofcase =
locale != "cy"
? "Submit your Statement of Case or select Yes to attach a separate Statement of Case Document"
: "Cyflwynwch eich Datganiad Achos neu dewiswch Ie i atodi Dogfen Datganiad Achos ar wahân";
} else {
errors.pinswg_statementofcase =
locale != "cy"
? "Submit your Statement of Case or select Yes to attach a separate Statement of Case Document"
: "Cyflwynwch eich Datganiad Achos neu dewiswch Ie i atodi Dogfen Datganiad Achos ar wahân";
}
}
}
if (values.hasOwnProperty("pinswg_costappliedforindicator")) {
if (values.pinswg_costappliedforindicator == "true") {
if (values.pinswg_attachcostapplication == "false") {
if (values.hasOwnProperty("pinswg_costapplication")) {
if (strippedHtml(values.pinswg_costapplication).length == 0)
errors.pinswg_costapplication =
locale != "cy"
? "Submit a Costs application or select Yes to attach a separate Costs application"
: "Cyflwyno cais Costau neu ddewis Ie i atodi cais Costau ar wahân";
} else {
errors.pinswg_costapplication =
locale != "cy"
? "Submit a Costs application or select Yes to attach a separate Costs application"
: "Cyflwyno cais Costau neu ddewis Ie i atodi cais Costau ar wahân";
}
}
}
}
return errors;
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(
reduxForm({
form: "appealForm",
destroyOnUnmount: false,
enableReinitialize: true, // this is needed!!
validate
})(BuildSection)
);