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:
@@ -12,15 +12,26 @@ import {
|
||||
setFormComplete
|
||||
} from "../../store/appealType/action";
|
||||
import BuildCheckRow from "./buildcheckrow";
|
||||
|
||||
import { generateAppealPDF } from "../../actions/services/documentService";
|
||||
import { sendCaseCompleteMessage } from "../../actions/services/portalService";
|
||||
import {
|
||||
bytesToSize,
|
||||
getThumbnailIconByExtension,
|
||||
updateLinks,
|
||||
getDocLink
|
||||
} from "../utils";
|
||||
import {
|
||||
dedupeFilesListByName,
|
||||
removeDuplicatesByKey
|
||||
} from "../../lib/newappeal/fileListHelpers";
|
||||
import {
|
||||
generateAppealPDFEffect,
|
||||
sendCaseCompleteMessageEffect
|
||||
} from "../../lib/newappeal/journeyEffects";
|
||||
import CheckSectionHeading from "./buildCheckSection/CheckSectionHeading";
|
||||
import ConfirmationCheckboxGroup from "./buildCheckSection/ConfirmationCheckboxGroup";
|
||||
import DocsOfflineNotice from "./buildCheckSection/DocsOfflineNotice";
|
||||
import FinalisingStatePanel from "./buildCheckSection/FinalisingStatePanel";
|
||||
import SectionReviewList from "./buildCheckSection/SectionReviewList";
|
||||
import SubmitActionsPanel from "./buildCheckSection/SubmitActionsPanel";
|
||||
|
||||
let BuildCheckSection = (props) => {
|
||||
useEffect(() => {
|
||||
@@ -44,6 +55,11 @@ let BuildCheckSection = (props) => {
|
||||
docsOffline
|
||||
} = props;
|
||||
|
||||
const legacyProps = props.props;
|
||||
const legacyAppealType = legacyProps.appealType;
|
||||
const legacyFormState = legacyProps.form;
|
||||
const legacyAccountDetails = legacyProps.accountDetails;
|
||||
|
||||
const parser = new DOMParser();
|
||||
var doc = parser.parseFromString(props.formXML, "text/xml");
|
||||
var titles = xpath.select(
|
||||
@@ -78,7 +94,7 @@ let BuildCheckSection = (props) => {
|
||||
|
||||
let buildAppealFilesArray = [];
|
||||
//console.log("attached docs: - ", buildAppealFilesArray);
|
||||
buildAppealFilesArray = props.props.appealType.fileList?.value[0] || [];
|
||||
buildAppealFilesArray = legacyAppealType.fileList?.value[0] || [];
|
||||
//let filesUploadObj = buildAppealFilesArray;
|
||||
// let filesUploadObj = props.appealType.fileList.hasOwnProperty("value")
|
||||
// ? props.appealType.fileList.value[0]
|
||||
@@ -97,28 +113,18 @@ let BuildCheckSection = (props) => {
|
||||
});
|
||||
//console.log(buildAppealFilesArray);
|
||||
|
||||
function removeDuplicates(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
|
||||
}
|
||||
});
|
||||
}
|
||||
buildAppealFilesArray = removeDuplicatesByKey(
|
||||
buildAppealFilesArray,
|
||||
"name"
|
||||
);
|
||||
|
||||
buildAppealFilesArray = removeDuplicates(buildAppealFilesArray, "name");
|
||||
|
||||
let pdfObj = props.props.form.appealForm.values;
|
||||
let pdfObj = legacyFormState.appealForm.values;
|
||||
|
||||
pdfObj = updateLinks(pdfObj);
|
||||
|
||||
Object.assign(pdfObj, {
|
||||
"filesList": buildAppealFilesArray,
|
||||
"containerID": props.props.accountDetails.containerID,
|
||||
"containerID": legacyAccountDetails.containerID,
|
||||
"casefolderID": props.appealType.caseReference.ticketnumber
|
||||
});
|
||||
|
||||
@@ -152,19 +158,16 @@ let BuildCheckSection = (props) => {
|
||||
const finaliseAppeal = async () => {
|
||||
//console.log("finalising appeal:", pdfObj);
|
||||
|
||||
const uniqueArray = pdfObj.filesList.filter(
|
||||
(value, index, self) =>
|
||||
index === self.findIndex((t) => t.name === value.name)
|
||||
);
|
||||
const uniqueArray = dedupeFilesListByName(pdfObj.filesList);
|
||||
|
||||
pdfObj.filesList = uniqueArray;
|
||||
pdfObj.locale = locale;
|
||||
|
||||
confirmSections
|
||||
? (setFinaliseAppealProcess(true),
|
||||
await generateAppealPDF(
|
||||
await generateAppealPDFEffect(
|
||||
pdfObj,
|
||||
props.props.accountDetails.containerID,
|
||||
legacyAccountDetails.containerID,
|
||||
props.appealType.caseReference.ticketnumber,
|
||||
router.query.appealtypes,
|
||||
pdfObj.filesList
|
||||
@@ -172,10 +175,10 @@ let BuildCheckSection = (props) => {
|
||||
)
|
||||
.then((data) => {
|
||||
console.log("have generated pdf:", data);
|
||||
sendCaseCompleteMessage(
|
||||
props.props.accountDetails.containerID,
|
||||
sendCaseCompleteMessageEffect(
|
||||
legacyAccountDetails.containerID,
|
||||
props.appealType.caseReference.ticketnumber,
|
||||
props.props.accountDetails.accountDetails
|
||||
legacyAccountDetails.accountDetails
|
||||
.pinswg_typeofinvolvement
|
||||
);
|
||||
})
|
||||
@@ -197,18 +200,15 @@ let BuildCheckSection = (props) => {
|
||||
try {
|
||||
setDownloadInProgress(true);
|
||||
|
||||
const uniqueArray = pdfObj.filesList.filter(
|
||||
(value, index, self) =>
|
||||
index === self.findIndex((t) => t.name === value.name)
|
||||
);
|
||||
const uniqueArray = dedupeFilesListByName(pdfObj.filesList);
|
||||
|
||||
pdfObj.filesList = uniqueArray;
|
||||
pdfObj.locale = locale;
|
||||
|
||||
const containerID =
|
||||
props.accountDetails?.containerID ||
|
||||
props.props?.accountDetails?.containerID ||
|
||||
props.props?.props?.accountDetails?.containerID;
|
||||
legacyProps?.accountDetails?.containerID ||
|
||||
legacyProps?.props?.accountDetails?.containerID;
|
||||
const caseRef =
|
||||
props?.currentView?.caseReference?.ticketnumber ||
|
||||
props?.appealType?.caseReference?.ticketnumber;
|
||||
@@ -221,7 +221,7 @@ let BuildCheckSection = (props) => {
|
||||
return;
|
||||
}
|
||||
|
||||
const pdfBlob = await generateAppealPDF(
|
||||
const pdfBlob = await generateAppealPDFEffect(
|
||||
pdfObj,
|
||||
containerID,
|
||||
caseRef,
|
||||
@@ -253,10 +253,8 @@ let BuildCheckSection = (props) => {
|
||||
<div className="govuk-grid-row" key={1222}>
|
||||
<div className="govuk-grid-column-full">
|
||||
<div>
|
||||
<h1 className="govuk-heading-m">
|
||||
Are these answers correct?
|
||||
</h1>
|
||||
<dl className="govuk-summary-list ">
|
||||
<CheckSectionHeading title="Are these answers correct?" />
|
||||
<SectionReviewList>
|
||||
{Object.keys(titles).map((key) => (
|
||||
<div key={key}>
|
||||
<h2 className="govuk-heading-m govuk-!-margin-top-9">
|
||||
@@ -274,7 +272,7 @@ let BuildCheckSection = (props) => {
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</dl>
|
||||
</SectionReviewList>
|
||||
{/* <dl className="govuk-summary-list govuk-!-margin-bottom-9 at-summary-list">
|
||||
{buildAppealFilesArray.length > 0
|
||||
? buildAppealFilesArray.map((blob, i) => {
|
||||
@@ -329,120 +327,61 @@ let BuildCheckSection = (props) => {
|
||||
</dl> */}
|
||||
</div>
|
||||
{finaliseAppealProcess ? (
|
||||
<div className="">
|
||||
<h3 className="govuk-heading-m govuk-!-margin-top-9">
|
||||
{t("newappeal:new-appeal-finalising-heading")}
|
||||
</h3>
|
||||
<p className="govuk-body">
|
||||
{t("newappeal:new-appeal-finalising-label")}
|
||||
</p>
|
||||
<p className="govuk-body textloading">
|
||||
{t("newappeal:new-appeal-wait-label")}
|
||||
</p>
|
||||
</div>
|
||||
<FinalisingStatePanel
|
||||
heading={t("newappeal:new-appeal-finalising-heading")}
|
||||
label={t("newappeal:new-appeal-finalising-label")}
|
||||
waitLabel={t("newappeal:new-appeal-wait-label")}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<div className="govuk-form-group ">
|
||||
<fieldset className="govuk-fieldset">
|
||||
<div className="govuk-checkboxes govuk-checkboxes--small">
|
||||
<div className="govuk-checkboxes__item">
|
||||
<input
|
||||
name="pinswg_downloadAppealForm"
|
||||
id="pinswg_downloadAppealForm"
|
||||
type="checkbox"
|
||||
className="govuk-checkboxes__input"
|
||||
checked={downloadAppealForm}
|
||||
onChange={(e) => {
|
||||
setDownloadAppealForm(
|
||||
e.target.checked
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<label
|
||||
className="govuk-label govuk-checkboxes__label"
|
||||
htmlFor="pinswg_downloadAppealForm"
|
||||
>
|
||||
{t(
|
||||
"newappeal:new-appeal-check-download-label"
|
||||
)}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="govuk-checkboxes govuk-checkboxes--small">
|
||||
<div className="govuk-checkboxes__item">
|
||||
<input
|
||||
name="pinswg_checkconfirmation"
|
||||
id="pinswg_checkconfirmation"
|
||||
type="checkbox"
|
||||
className="govuk-checkboxes__input"
|
||||
value=""
|
||||
onChange={(e) => {
|
||||
setConfirmSections(
|
||||
!confirmSections
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<label
|
||||
className="govuk-label govuk-checkboxes__label"
|
||||
htmlFor="pinswg_checkconfirmation"
|
||||
>
|
||||
{t(
|
||||
"newappeal:new-appeal-check-confirm-label"
|
||||
)}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div>
|
||||
<p className="govuk-body">
|
||||
{t(
|
||||
"newappeal:new-appeal-check-confirm-paragraph-one"
|
||||
<ConfirmationCheckboxGroup
|
||||
downloadAppealForm={downloadAppealForm}
|
||||
onDownloadChange={(e) => {
|
||||
setDownloadAppealForm(e.target.checked);
|
||||
}}
|
||||
onConfirmChange={(e) => {
|
||||
setConfirmSections(!confirmSections);
|
||||
}}
|
||||
downloadLabel={t(
|
||||
"newappeal:new-appeal-check-download-label"
|
||||
)}
|
||||
confirmLabel={t(
|
||||
"newappeal:new-appeal-check-confirm-label"
|
||||
)}
|
||||
paragraphOne={t(
|
||||
"newappeal:new-appeal-check-confirm-paragraph-one"
|
||||
)}
|
||||
paragraphTwo={t(
|
||||
"newappeal:new-appeal-check-confirm-paragraph-two"
|
||||
)}
|
||||
paragraphTwoLink={
|
||||
<Link
|
||||
target="_blank"
|
||||
href={t(
|
||||
"newappeal:new-appeal-check-confirm-paragraph-two-link"
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="govuk-body">
|
||||
>
|
||||
{t(
|
||||
"newappeal:new-appeal-check-confirm-paragraph-two"
|
||||
)}{" "}
|
||||
<Link
|
||||
target="_blank"
|
||||
href={t(
|
||||
"newappeal:new-appeal-check-confirm-paragraph-two-link"
|
||||
)}
|
||||
>
|
||||
{t(
|
||||
"newappeal:new-appeal-check-confirm-paragraph-two-link"
|
||||
)}
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
"newappeal:new-appeal-check-confirm-paragraph-two-link"
|
||||
)}
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
|
||||
<div className="govuk-button-group">
|
||||
<SubmitActionsPanel>
|
||||
{ShowDocLinks ? (
|
||||
<>
|
||||
<div className="govuk-warning-text ">
|
||||
<span
|
||||
className="govuk-warning-text__icon"
|
||||
aria-hidden="true"
|
||||
>
|
||||
!
|
||||
</span>
|
||||
<strong className="govuk-warning-text__text govuk-!-margin-top-2">
|
||||
<span className="govuk-visually-hidden">
|
||||
Notice
|
||||
</span>
|
||||
<DocsOfflineNotice
|
||||
noticeText={t(
|
||||
"myportal:docsoffline-newappeal-label"
|
||||
)}
|
||||
returnLink={
|
||||
<Link className="govuk-link" href="/">
|
||||
{t(
|
||||
"myportal:docsoffline-newappeal-label"
|
||||
"newappeal:return-to-myportal-link"
|
||||
)}
|
||||
{" "}
|
||||
</strong>
|
||||
</div>{" "}
|
||||
<Link className="govuk-link" href="/">
|
||||
{t("newappeal:return-to-myportal-link")}
|
||||
</Link>
|
||||
</>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<>
|
||||
<button
|
||||
@@ -468,7 +407,7 @@ let BuildCheckSection = (props) => {
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</SubmitActionsPanel>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user