Merged PR 2242: Refactor: New Appeal flow structural cleanup (Slices 1–8, no behaviour change)
## Summary This PR merges the completed new-appeal refactor stream (Slices 1–8) into SIPS-Development. This refactor was executed in controlled slices with regression validation at each step. ## Scope Structural and readability improvements only: - XML/form derivation extraction - payload and file helper extraction - side-effect facade introduction - BuildSection and BuildCheckSection decomposition - BuildCheckRow formatter map refactor - nested prop boundary cleanup - start-flow cleanup (CreateCase / AboutYou) ## Behaviour No intended behavioural changes. The following were explicitly preserved: - S78 journey behaviour - payload shapes and field names/ids - HASCAS mapping logic - appellant/agent branching - validation rules and messages - redirect/query parameters (`lpa`, `apt`, `id`) - navigation and side-effect sequencing - EN/CY output parity ## Validation Full regression has been performed on: - start flow (CreateCase / AboutYou) - save and resume flows - file upload handling - check answers rendering - submit/finalisation sequence - confirmation flow - CRM insertion path - EN/CY parity Additional checks: - docsOffline branch behaviour - completion and partial-save email paths - negative-path validation scenarios - lint (warnings baseline unchanged) ## Risk Low: - changes are structural only - no business logic changes - no contract changes ## Rollback Safe rollback via reverting this merge commit. ## Notes This refactor reduces coupling and prepares the new-appeal flow for future appeal-type expansion. Related work items: #22570, #22576, #22577, #22583, #22586, #22587, #22588, #22590
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
export const mergeWithExistingFilesList = (buildAppealFilesArray, values) => {
|
||||
return values.hasOwnProperty("filesList")
|
||||
? (buildAppealFilesArray.concat(values.filesList),
|
||||
buildAppealFilesArray.filter(function (item, idx) {
|
||||
return item.name;
|
||||
}))
|
||||
: buildAppealFilesArray;
|
||||
};
|
||||
|
||||
export const removeDuplicatesByKey = (arr, key) => {
|
||||
const seen = new Set();
|
||||
return arr.filter((item) => {
|
||||
const value = item[key];
|
||||
if (seen.has(value)) {
|
||||
return false; // Duplicate found
|
||||
} else {
|
||||
seen.add(value); // Add value to the set
|
||||
return true; // Keep the item
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const dedupeFilesListByName = (filesList) => {
|
||||
return filesList.filter(
|
||||
(value, index, self) =>
|
||||
index === self.findIndex((t) => t.name === value.name)
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,102 @@
|
||||
import xpath from "xpath";
|
||||
|
||||
export const parseXml = (xmlStr) => {
|
||||
const parser = new DOMParser();
|
||||
return parser.parseFromString(xmlStr, "text/xml");
|
||||
};
|
||||
|
||||
export const selectCurrentSectionTitleDescriptions = (doc, currentSection) => {
|
||||
return xpath.select(
|
||||
"//form/tabs/tab[" + currentSection + " ]/labels/label/@description",
|
||||
doc
|
||||
);
|
||||
};
|
||||
|
||||
export const selectCurrentSectionRows = (doc, currentSection) => {
|
||||
return xpath.select(
|
||||
"/form/tabs/tab[" +
|
||||
currentSection +
|
||||
"]/columns//sections/section/rows/row",
|
||||
doc
|
||||
);
|
||||
};
|
||||
|
||||
export const selectFormTabs = (doc) => {
|
||||
return xpath.select("/form/tabs", doc);
|
||||
};
|
||||
|
||||
export const selectAllTabTitleDescriptions = (doc) => {
|
||||
return xpath.select("//form/tabs/tab[*]/labels/label/@description", doc);
|
||||
};
|
||||
|
||||
export const parseRowOuterHTML = (outerHTML) => {
|
||||
const parser = new DOMParser();
|
||||
return parser.parseFromString(outerHTML, "text/xml");
|
||||
};
|
||||
|
||||
export const selectRowLabelDescriptions = (doc) => {
|
||||
return xpath.select("//label/@description", doc);
|
||||
};
|
||||
|
||||
export const selectRowFieldType = (doc) => {
|
||||
return xpath.select("//@classid", doc);
|
||||
};
|
||||
|
||||
export const selectRowValidation = (doc) => {
|
||||
return xpath.select("//@validation", doc);
|
||||
};
|
||||
|
||||
export const selectRowMaxFieldLength = (doc) => {
|
||||
return xpath.select("//@maxFieldLength", doc);
|
||||
};
|
||||
|
||||
export const selectRowMaxSubField = (doc) => {
|
||||
return xpath.select("//@maxsubfield", doc);
|
||||
};
|
||||
|
||||
export const selectRowDataFieldName = (doc) => {
|
||||
return xpath.select("//@datafieldname", doc);
|
||||
};
|
||||
|
||||
export const selectRowDataFieldContent = (doc) => {
|
||||
return xpath.select("//@datafieldcontent", doc);
|
||||
};
|
||||
|
||||
export const selectRowParentField = (doc) => {
|
||||
return xpath.select("//@parentField", doc);
|
||||
};
|
||||
|
||||
export const selectRowParentFieldShowOnValue = (doc) => {
|
||||
return xpath.select("//@parentFieldShowOnValue", doc);
|
||||
};
|
||||
|
||||
export const selectRowRequiredDocumentValue = (doc) => {
|
||||
return xpath.select("//@requiredDocumentValue", doc);
|
||||
};
|
||||
|
||||
export const selectRowRequiredDocumentLabel = (doc) => {
|
||||
return xpath.select("//@requiredDocumentLabel", doc);
|
||||
};
|
||||
|
||||
export const selectRowDocumentTypeCode = (doc) => {
|
||||
return xpath.select("//@ishareDocumentCode", doc);
|
||||
};
|
||||
|
||||
export const selectRowHint = (doc) => {
|
||||
return xpath.select("//label/@hint", doc);
|
||||
};
|
||||
|
||||
export const selectRowDateStart = (doc) => {
|
||||
return xpath.select("//@dateStart", doc);
|
||||
};
|
||||
|
||||
export const selectRowDateEnd = (doc) => {
|
||||
return xpath.select("//@dateEnd", doc);
|
||||
};
|
||||
|
||||
export const selectErrorFieldLabelDescription = (doc, whichField) => {
|
||||
return xpath.select(
|
||||
"//*[control/@id='" + whichField + "']//@description",
|
||||
doc
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,61 @@
|
||||
import { uploadFiles } from "../../actions/services/documentService";
|
||||
import { sendEmail } from "../../actions/services/notifyService";
|
||||
import { sendCaseCompleteMessage } from "../../actions/services/portalService";
|
||||
import { generateAppealPDF } from "../../actions/services/documentService";
|
||||
|
||||
export const uploadAppealFilesEffect = (
|
||||
dataObj,
|
||||
fileListObj,
|
||||
containerID,
|
||||
caseReference
|
||||
) => {
|
||||
return uploadFiles(dataObj, fileListObj, containerID, caseReference);
|
||||
};
|
||||
|
||||
export const sendPartialSaveEmailEffect = (
|
||||
templateId,
|
||||
emailAddress,
|
||||
personalisation,
|
||||
reference
|
||||
) => {
|
||||
return sendEmail(templateId, emailAddress, personalisation, reference);
|
||||
};
|
||||
|
||||
export const sendCompletionEmailEffect = (
|
||||
templateId,
|
||||
emailAddress,
|
||||
personalisation,
|
||||
reference
|
||||
) => {
|
||||
return sendEmail(templateId, emailAddress, personalisation, reference);
|
||||
};
|
||||
|
||||
export const generateAppealPDFEffect = (
|
||||
pdfObj,
|
||||
containerID,
|
||||
caseReference,
|
||||
appealType,
|
||||
filesList,
|
||||
options
|
||||
) => {
|
||||
return generateAppealPDF(
|
||||
pdfObj,
|
||||
containerID,
|
||||
caseReference,
|
||||
appealType,
|
||||
filesList,
|
||||
options
|
||||
);
|
||||
};
|
||||
|
||||
export const sendCaseCompleteMessageEffect = (
|
||||
containerID,
|
||||
caseReference,
|
||||
typeOfInvolvement
|
||||
) => {
|
||||
return sendCaseCompleteMessage(
|
||||
containerID,
|
||||
caseReference,
|
||||
typeOfInvolvement
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
export const normalizeYesNoBooleans = (updateBody) => {
|
||||
updateBody = JSON.stringify(updateBody);
|
||||
updateBody = updateBody.replace(/:\"Yes\"/gm, `:true`);
|
||||
updateBody = updateBody.replace(/:\"No\"/gm, `:false`);
|
||||
updateBody = JSON.parse(updateBody);
|
||||
|
||||
return updateBody;
|
||||
};
|
||||
|
||||
export const removeNullKeys = (updateBody) => {
|
||||
Object.keys(updateBody).forEach((key) => {
|
||||
if (updateBody[key] === null) {
|
||||
delete updateBody[key];
|
||||
}
|
||||
});
|
||||
|
||||
return updateBody;
|
||||
};
|
||||
|
||||
export const stripInternalKeys = (updateBody) => {
|
||||
Object.keys(updateBody).forEach((key) => {
|
||||
if (key.indexOf("_") == 0) {
|
||||
delete updateBody[key];
|
||||
}
|
||||
});
|
||||
|
||||
return updateBody;
|
||||
};
|
||||
Reference in New Issue
Block a user