diff --git a/.env.local b/.env.local index 548fde8a..9a787f68 100644 --- a/.env.local +++ b/.env.local @@ -101,6 +101,14 @@ CRMURL_VERSION = "v8.2" # CRMURL = "wg-pp-pedw.crm11.dynamics.com" # CRMURL_VERSION = "v9.2" +# D365 Prod WGO +# CLIENT_ID = 3e4141a3-1fbd-454e-98f0-7f3a4f14a3cc +# CLIENT_SECRET = tFk8Q~E.R-HFjROTu1sRKqwb_ONzy05uPYoF6awR +# RELAY_ROOT = https://ar-ns-lz-pedw-d365prod-uks-01.servicebus.windows.net/ar-hc-lz-pedw-d365prod-uks-01/ +# RELAYURI = "ar-ns-lz-pedw-d365prod-uks-01.servicebus.windows.net" +# RELAYPATH = "ar-hc-lz-pedw-d365prod-uks-01" +# CRMURL = "wg-prod-pedw.crm11.dynamics.com" +# CRMURL_VERSION = "v9.2" //GOOGLE_TAG_MANAGER = GTM-T78CBC3 @@ -152,6 +160,10 @@ DATABASE_URL = sqlserver://sql-srv-plt-pedw-cnr-uks-01.database.windows.net:1433 // D365 PPE sql server # DATABASE_URL = sqlserver://sql-srv-plt-pedw-d365ppe-uks-01.database.windows.net:1433;database=PEDW;user=PedwSqlAdmin;password=GhWKr62F5sQ69dZx;encrypt=true;trustServerCertificate=true;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryPassword +// D365 Prod sql server +# DATABASE_URL = sqlserver://sql-srv-plt-pedw-d365prod-uks-01.database.windows.net:1433;database=PEDW;user=PedwSqlAdmin;password=GhWKr62F5sQ69dZx;encrypt=true;trustServerCertificate=true;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryPassword + + SECRET = SuperSecret @@ -173,9 +185,9 @@ AZURE_STORAGE_ACCOUNT_KEY = MmrsrCjBfop9pI2oImsP/+lJUWU2DrXsAB8nq5bOVROTmPovSGxj AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwdevuks.blob.core.windows.net // New test key -# AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwtestuks" -# AZURE_STORAGE_ACCOUNT_KEY = 5NdDO9GGlbTFLHFOXZRw8H2C0Ow5bFTvHwUHEbStyzg2mbd1uwHSeBSvM/dkN+HfdwrFzqAkwL5P+AStdO6cig== -# AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwtestuks.blob.core.windows.net +AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwtestuks" +AZURE_STORAGE_ACCOUNT_KEY = 5NdDO9GGlbTFLHFOXZRw8H2C0Ow5bFTvHwUHEbStyzg2mbd1uwHSeBSvM/dkN+HfdwrFzqAkwL5P+AStdO6cig== +AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwtestuks.blob.core.windows.net // New preprod key # AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwppeuks" @@ -216,6 +228,11 @@ AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwdevuks.blob.core.windows.net # AZURE_STORAGE_ACCOUNT_KEY = xQz4FWDnQDE09uPOCj1t7axRiquvZG9vbxL88ywzVsJnTsAgewrHnuAGkxGPBCp2xGE53ffYOme6+AStSr8OoQ== # AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwd365ppeuks.blob.core.windows.net +# D365 Prod key +# AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwd365produks" +# AZURE_STORAGE_ACCOUNT_KEY = DvKcWhDpFKMFdVXFF2SqDG0sYQ3AkNCmJUBG0cvgzi5NBHS4Ahd2hPAlfA3hGi2EbohUag3vCucK+ASt1IdBhA== +# AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwd365produks.blob.core.windows.net + AZURE_PEDW_CONTAINER = "pedwapplications" AZURE_PEDW_QUEUE_ENDPOINT = https://$AZURE_STORAGE_ACCOUNT_NAME.queue.core.windows.net @@ -235,7 +252,7 @@ APPLICATIONINSIGHTS_CONNECTIONSTRING = InstrumentationKey=7a06e24a-793c-47bc-898 // Test Connection string -//NEXT_PUBLIC_APP_INSIGHT = InstrumentationKey=cc60e8e7-5b30-4c2b-a176-8b96b21b12df;IngestionEndpoint=https://ukwest-0.in.applicationinsights.azure.com/;LiveEndpoint=https://ukwest.livediagnostics.monitor.azure.com/;ApplicationId=2a4094be-6fd1-46ab-a67d-5f241692b129 +NEXT_PUBLIC_APP_INSIGHT = InstrumentationKey=cc60e8e7-5b30-4c2b-a176-8b96b21b12df;IngestionEndpoint=https://ukwest-0.in.applicationinsights.azure.com/;LiveEndpoint=https://ukwest.livediagnostics.monitor.azure.com/;ApplicationId=2a4094be-6fd1-46ab-a67d-5f241692b129 // Preprod Connection string //NEXT_PUBLIC_APP_INSIGHT = InstrumentationKey=7370f0f9-834d-4c7a-b3c4-9951fcad5ad2;IngestionEndpoint=https://ukwest-0.in.applicationinsights.azure.com/;LiveEndpoint=https://ukwest.livediagnostics.monitor.azure.com/;ApplicationId=04362cb7-6dfc-469e-8274-12243e8be851 diff --git a/components/admin/tabs/documents.js b/components/admin/tabs/documents.js index 94bc359a..a95e4ab6 100644 --- a/components/admin/tabs/documents.js +++ b/components/admin/tabs/documents.js @@ -5,7 +5,7 @@ import { useRouter } from "next/router"; import { useCallback, useEffect, useRef, useState } from "react"; import { connect } from "react-redux"; import transLookup from "../../../data/lookuptranslations.json"; -import { formatDates } from "../../utils"; +import { formatDates, getDocLink } from "../../utils"; import PaginationControl from "../../../components/case/pagination"; import DocumentLink from "../../utils/downloads"; import { useDownloadQueue } from "../../utils/downloadmanager"; @@ -305,37 +305,7 @@ const DocumentsTab = (props) => { setSelectedDocumentOrigin("all") ); }; - let ShowDocLinks = false; - let checkShowDocLinks = docsOffline != false ? true : false; - - const getDocLink = (docsOffline) => { - var startTime = docsOffline.split(",")[0]; - var endTime = docsOffline.split(",")[1]; - - // console.log(startTime); - // console.log(endTime); - - var currentDate = new Date(); - - var startDate = new Date(currentDate.getTime()); - startDate.setHours(startTime.split(":")[0]); - startDate.setMinutes(startTime.split(":")[1]); - startDate.setSeconds(startTime.split(":")[2]); - - var endDate = new Date(currentDate.getTime()); - endDate.setHours(endTime.split(":")[0]); - endDate.setMinutes(endTime.split(":")[1]); - endDate.setSeconds(endTime.split(":")[2]); - - // console.log(startDate); - // console.log(endDate); - // console.log(currentDate); - - var valid = startDate < currentDate && endDate > currentDate; - ShowDocLinks = valid; - }; - - checkShowDocLinks && getDocLink(docsOffline); + let ShowDocLinks = getDocLink(docsOffline); const FilteredDocumentView = (documentDetailsArr) => { documentDetailsArr = documentDetailsArr.value; diff --git a/components/case/documents.js b/components/case/documents.js index 35f6db4a..37a12ce5 100644 --- a/components/case/documents.js +++ b/components/case/documents.js @@ -5,7 +5,7 @@ import { useRouter } from "next/router"; import { useCallback, useEffect, useRef, useState } from "react"; import { connect } from "react-redux"; import transLookup from "../../data/lookuptranslations.json"; -import { formatDates } from "../utils"; +import { formatDates, getDocLink } from "../utils"; import PaginationControl from "./pagination"; import { sendGAEvent } from "@next/third-parties/google"; @@ -90,37 +90,7 @@ const DocumentDetails = (props) => { setCurrentPage(1) ); }; - let ShowDocLinks = false; - let checkShowDocLinks = docsOffline != false ? true : false; - - const getDocLink = (docsOffline) => { - var startTime = docsOffline.split(",")[0]; - var endTime = docsOffline.split(",")[1]; - - // console.log(startTime); - // console.log(endTime); - - var currentDate = new Date(); - - var startDate = new Date(currentDate.getTime()); - startDate.setHours(startTime.split(":")[0]); - startDate.setMinutes(startTime.split(":")[1]); - startDate.setSeconds(startTime.split(":")[2]); - - var endDate = new Date(currentDate.getTime()); - endDate.setHours(endTime.split(":")[0]); - endDate.setMinutes(endTime.split(":")[1]); - endDate.setSeconds(endTime.split(":")[2]); - - // console.log(startDate); - // console.log(endDate); - // console.log(currentDate); - - var valid = startDate < currentDate && endDate > currentDate; - ShowDocLinks = valid; - }; - - checkShowDocLinks && getDocLink(docsOffline); + let ShowDocLinks = getDocLink(docsOffline); const DocumentView = (documentDetailsArr) => { documentDetailsArr = documentDetailsArr.value; diff --git a/components/case/representation/index.js b/components/case/representation/index.js index 27b9092c..5c894c8b 100644 --- a/components/case/representation/index.js +++ b/components/case/representation/index.js @@ -66,6 +66,7 @@ let MakeRepresentation = (props) => { initialValues, setCurrentReference, ticketnumber, + docsOffline, } = props; const formObj = props.props.form; let setCaseQueryObj = props[currentType] || {}; @@ -1105,6 +1106,7 @@ let MakeRepresentation = (props) => { questionnaireCount={questionnaireCount} finaliseAppealProcess={finaliseAppealProcess} setFinaliseAppealProcess={setFinaliseAppealProcess} + docsOffline={docsOffline} /> ) : ( <> diff --git a/components/case/representation/representationCompleteSubmit.js b/components/case/representation/representationCompleteSubmit.js index a4302dd7..b51830ab 100644 --- a/components/case/representation/representationCompleteSubmit.js +++ b/components/case/representation/representationCompleteSubmit.js @@ -13,6 +13,7 @@ import { getThumbnailIconByExtension, formatDates, updateLinks, + getDocLink, } from "../../utils"; import { @@ -41,7 +42,11 @@ const RepCompleteSubmit = (props) => { questionnaireCount, finaliseAppealProcess, setCurrentReference, + docsOffline, } = props; + + let ShowDocLinks = getDocLink(docsOffline); + const { acceptedFiles, getRootProps, getInputProps } = useDropzone(); const files = acceptedFiles.map((file) => (
  • @@ -230,6 +235,7 @@ const RepCompleteSubmit = (props) => { } const checkRepDatePassed = () => { + return false; if (repFormData.representationType == "Questionnaire") { return false; } else { @@ -603,6 +609,7 @@ const RepCompleteSubmit = (props) => { "myrepresentations:rep-check-tandc-para-three" )}

    + {checkRepDatePassed() ? (
    @@ -641,6 +648,32 @@ const RepCompleteSubmit = (props) => { {t("myrepresentations:rep-wait-label")}

    + ) : ShowDocLinks ? ( + <> + {" "} +
    + + + + Notice + + {t( + "myrepresentations:docsoffline-reps-label" + )} + {" "} + +
    {" "} + + {t( + "myrepresentations:return-to-myportal-link" + )} + + ) : ( <>
    diff --git a/components/case/summary.js b/components/case/summary.js index ed5aa7ff..b053f450 100644 --- a/components/case/summary.js +++ b/components/case/summary.js @@ -104,38 +104,6 @@ const CaseSummary = (props) => { ? true : false; - let ShowDocLinks = false; - let checkShowDocLinks = docsOffline != false ? true : false; - - const getDocLink = (docsOffline) => { - var startTime = docsOffline.split(",")[0]; - var endTime = docsOffline.split(",")[1]; - - // console.log(startTime); - // console.log(endTime); - - var currentDate = new Date(); - - var startDate = new Date(currentDate.getTime()); - startDate.setHours(startTime.split(":")[0]); - startDate.setMinutes(startTime.split(":")[1]); - startDate.setSeconds(startTime.split(":")[2]); - - var endDate = new Date(currentDate.getTime()); - endDate.setHours(endTime.split(":")[0]); - endDate.setMinutes(endTime.split(":")[1]); - endDate.setSeconds(endTime.split(":")[2]); - - // console.log(startDate); - // console.log(endDate); - // console.log(currentDate); - - var valid = startDate < currentDate && endDate > currentDate; - ShowDocLinks = valid; - }; - - checkShowDocLinks && getDocLink(docsOffline); - const selectWatchedCase = (loggedInUser, incidentID, appealType) => { let updateBody = { "pinswg_WatchedCase@odata.bind": "/incidents(" + incidentID + ")", diff --git a/components/myportal/makenewappeal.js b/components/myportal/makenewappeal.js index ee1ac54a..a2ceedd7 100644 --- a/components/myportal/makenewappeal.js +++ b/components/myportal/makenewappeal.js @@ -1,6 +1,7 @@ import useTranslation from "next-translate/useTranslation"; import Link from "next/link"; import { useRouter } from "next/router"; +import { getDocLink } from "../utils"; export default function MakeNewAppeal(props) { let { t } = useTranslation(); @@ -10,37 +11,7 @@ export default function MakeNewAppeal(props) { const router = useRouter(); const { locale } = router; - let ShowDocLinks = false; - let checkShowDocLinks = docsOffline != false ? true : false; - - const getDocLink = (docsOffline) => { - var startTime = docsOffline.split(",")[0]; - var endTime = docsOffline.split(",")[1]; - - // console.log(startTime); - // console.log(endTime); - - var currentDate = new Date(); - - var startDate = new Date(currentDate.getTime()); - startDate.setHours(startTime.split(":")[0]); - startDate.setMinutes(startTime.split(":")[1]); - startDate.setSeconds(startTime.split(":")[2]); - - var endDate = new Date(currentDate.getTime()); - endDate.setHours(endTime.split(":")[0]); - endDate.setMinutes(endTime.split(":")[1]); - endDate.setSeconds(endTime.split(":")[2]); - - // console.log(startDate); - // console.log(endDate); - // console.log(currentDate); - - var valid = startDate < currentDate && endDate > currentDate; - ShowDocLinks = valid; - }; - - console.log("docsOffline", docsOffline, getDocLink(docsOffline)); + let ShowDocLinks = getDocLink(docsOffline); return (
    diff --git a/components/newappeal/buildchecksection.js b/components/newappeal/buildchecksection.js index 58030988..6f18f630 100644 --- a/components/newappeal/buildchecksection.js +++ b/components/newappeal/buildchecksection.js @@ -18,6 +18,7 @@ import { bytesToSize, getThumbnailIconByExtension, updateLinks, + getDocLink, } from "../utils"; let BuildCheckSection = (props) => { @@ -39,6 +40,7 @@ let BuildCheckSection = (props) => { setCurrentSection, updateCurrentSection, mandatoryFieldsData, + docsOffline, } = props; const parser = new DOMParser(); @@ -180,6 +182,8 @@ let BuildCheckSection = (props) => { : setConfirmSections(false); }; + let ShowDocLinks = getDocLink(docsOffline); + return (
    @@ -327,23 +331,54 @@ let BuildCheckSection = (props) => {
    )} diff --git a/components/newappeal/buildfield.js b/components/newappeal/buildfield.js index 5af2c197..29e6e919 100644 --- a/components/newappeal/buildfield.js +++ b/components/newappeal/buildfield.js @@ -204,7 +204,7 @@ export default function BuildField(props) { uploadCount={uploadCount} setFileCount={setFileCount} setUploadCount={setUploadCount} - props={props?.props?.props} + props={props?.props?.props?.props} />
    ), diff --git a/components/newappeal/constants.js b/components/newappeal/constants.js new file mode 100644 index 00000000..1d094f96 --- /dev/null +++ b/components/newappeal/constants.js @@ -0,0 +1,2 @@ +// components/newappeal/constants.js +export const SECTION_COMPLETE = 9999; diff --git a/components/newappeal/newAppealFlow.js b/components/newappeal/newAppealFlow.js new file mode 100644 index 00000000..b8a78111 --- /dev/null +++ b/components/newappeal/newAppealFlow.js @@ -0,0 +1,48 @@ +// components/newappeal/NewAppealFlow.js +import React from "react"; +import BuildCheckSection from "./buildchecksection"; +import BuildSection from "./buildsection"; +import CompleteAppeal from "./complete"; +import { SECTION_COMPLETE } from "./constants"; + +export default function NewAppealFlow({ + formXML, + sectionCount, + currentSection, + onSubmit, + formTitle, + mandatoryFieldsData, + propsForChildren, + docsOffline, +}) { + if (currentSection === SECTION_COMPLETE) { + return ; + } + + if (currentSection === sectionCount + 1) { + return ( + + ); + } + + return ( + + ); +} diff --git a/components/newappeal/newAppealPageShell.js b/components/newappeal/newAppealPageShell.js new file mode 100644 index 00000000..b2c13561 --- /dev/null +++ b/components/newappeal/newAppealPageShell.js @@ -0,0 +1,112 @@ +// components/newappeal/NewAppealPageShell.js +import React from "react"; +import Head from "next/head"; +import { useRouter } from "next/router"; +import useTranslation from "next-translate/useTranslation"; + +import Breadcrumbs from "../breadcrumbs"; +import CookieBanner from "../cookieBanner"; +import Footer from "../footer"; +import Header from "../header"; +import TimeOut from "../timeout"; +import ServiceBanner from "../myportal/servicebanner"; + +export default function NewAppealPageShell({ + appealtypes, + formTitle, + footerLinks, + children, + propsForFooter, + propsForServiceBanner, +}) { + const router = useRouter(); + const { t } = useTranslation(); + + return ( +
    + + + {t("newappeal:page-title")} - {t("common:service-name")} + + + {/* Keep your existing meta structure */} + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + +
    + {children} +
    +
    + +
    +
    + + +
    + ); +} diff --git a/components/representation.js b/components/representation.js index 77ebb8c7..da9f4232 100644 --- a/components/representation.js +++ b/components/representation.js @@ -35,6 +35,7 @@ const CaseRepresentation = (props) => { props.setShowQuestionnaireSection } setCurrentReference={props.setCurrentReference} + docsOffline={props.docsOffline} />
    diff --git a/components/utils/index.js b/components/utils/index.js index 97a6cd64..bbd892dc 100644 --- a/components/utils/index.js +++ b/components/utils/index.js @@ -797,3 +797,30 @@ export const whichRepType = (props) => { return repType; }; + +export const getDocLink = (docsOffline) => { + var startTime = docsOffline.split(",")[0]; + var endTime = docsOffline.split(",")[1]; + + // console.log(startTime); + // console.log(endTime); + + var currentDate = new Date(); + + var startDate = new Date(currentDate.getTime()); + startDate.setHours(startTime.split(":")[0]); + startDate.setMinutes(startTime.split(":")[1]); + startDate.setSeconds(startTime.split(":")[2]); + + var endDate = new Date(currentDate.getTime()); + endDate.setHours(endTime.split(":")[0]); + endDate.setMinutes(endTime.split(":")[1]); + endDate.setSeconds(endTime.split(":")[2]); + + // console.log(startDate); + // console.log(endDate); + // console.log(currentDate); + + var valid = startDate < currentDate && endDate > currentDate; + return valid; +}; diff --git a/i18n.js b/i18n.js index 3b680589..272ba0ea 100644 --- a/i18n.js +++ b/i18n.js @@ -57,7 +57,7 @@ module.exports = { "/myportal/case/id/[incident]": ["case", "home"], "/myportal/addresssearch": ["search", "case", "myportal"], "/myportal/addresssearchresults": ["search", "case", "myportal"], - "/myportal/[appealtypes]": ["newappeal", "home"], + "/myportal/[appealtypes]": ["newappeal", "home", "myportal"], "/newappeal": ["newappeal", "home"], "/newappeal/*": ["newappeal", "home"], "/newappeal/[appealtypes]": ["newappeal", "home"], diff --git a/lib/forms/parseFormXml.js b/lib/forms/parseFormXml.js new file mode 100644 index 00000000..2f045417 --- /dev/null +++ b/lib/forms/parseFormXml.js @@ -0,0 +1,35 @@ +// lib/forms/parseFormXml.js +import xpath from "xpath"; + +/** + * NOTE: Your current page uses DOMParser, which is available in the browser. + * For SSR parsing you'd usually use xmldom or a similar package. + * + * This module supports BOTH: + * - Browser: pass DOMParser output doc + * - Server: if you later add xmldom, pass its doc here + */ + +export function getSectionCount(doc) { + const tabs = xpath.select("/form/tabs/tab[*]", doc); + return Array.isArray(tabs) ? tabs.length : 0; +} + +export function getTabTitles(doc) { + // same XPath you had + const titleAttrs = xpath.select( + "//form/tabs/tab[*]/labels/label[@description]/@description", + doc + ); + + if (!Array.isArray(titleAttrs)) return []; + // Attribute nodes differ by parser; be defensive: + return titleAttrs + .map((n) => (typeof n?.value === "string" ? n.value : n?.toString?.())) + .filter(Boolean); +} + +export function getTabs(doc) { + const tabs = xpath.select("//form/tabs/tab[*]", doc); + return Array.isArray(tabs) ? tabs : []; +} diff --git a/lib/forms/readFormXml.js b/lib/forms/readFormXml.js new file mode 100644 index 00000000..5278f7f2 --- /dev/null +++ b/lib/forms/readFormXml.js @@ -0,0 +1,24 @@ +// lib/forms/readFormXml.js +import fs from "fs"; +import path from "path"; + +/** + * Reads /data/formsxml/{appealtypes}.xml and normalises it. + * Returns { xmlStr } or throws on missing file. + */ +export function readFormXml(appealtypes) { + if (!appealtypes) throw new Error("readFormXml: appealtypes is required"); + + const configDirectory = path.resolve(process.cwd(), "data/formsxml"); + const filePath = path.join(configDirectory, `${appealtypes}.xml`); + + let xmlStr = fs.readFileSync(filePath, "utf8"); + + // Keep existing normalisation behaviour + xmlStr = xmlStr.replace(/\t/g, ""); + xmlStr = xmlStr.replace(/\n/g, ""); + xmlStr = xmlStr.replace(/> <"/g, "><"); + xmlStr = xmlStr.toString(); + + return { xmlStr, filePath }; +} diff --git a/lib/myportal/hydrateMyPortalAppealStore.js b/lib/myportal/hydrateMyPortalAppealStore.js new file mode 100644 index 00000000..e83dfd54 --- /dev/null +++ b/lib/myportal/hydrateMyPortalAppealStore.js @@ -0,0 +1,82 @@ +// lib/myportal/hydrateMyPortalAppealStore.js +import { + setContainerID, + setLoggedInUserEmail, + setLoggedInUserId, + setAccountDetails, +} from "../../store/accountDetails/action"; + +import { + setAppealLPA, + setAppealType, + setAppealTypeID, + setCaseReference as setCaseReferenceAction, + setFilesForAppeal, +} from "../../store/appealType/action"; + +import { + setAwaitingSubmissionDetails, + setAwaitingSubmissionFromBlob, +} from "../../store/awaitingSubmission/action"; + +import { setCurrentView, setLocale } from "../../store/currentView/action"; +import { setForm } from "../../store/formData/action"; + +/** + * Hydrates Redux store for resume flow in /myportal/[appealtypes] + */ +export function hydrateMyPortalAppealStore(store, ctx, data) { + const { query, locale } = ctx; + + const { + session, + loggedInUser, + loggedInUserEmail, + appealTypeData, + mandatoryFieldsData, + pickListData, + blobList, + blobProgress, + accountDetails, + awaitingSubmissionFromBlob, + xmlStr, + } = data; + + // Keep existing behaviour: write locale into store + store.dispatch(setLocale(locale)); + + // Build caseReference in the same shape you already use + const caseReference = { + ticketnumber: query.casereference, + incidentid: query.inid, // as per your file + caseDetails: blobProgress, + }; + + // Optional awaiting submission state setup + if (awaitingSubmissionFromBlob) { + store.dispatch( + setAwaitingSubmissionFromBlob(awaitingSubmissionFromBlob) + ); + store.dispatch( + setAwaitingSubmissionDetails(awaitingSubmissionFromBlob) + ); + store.dispatch( + setCurrentView({ + viewName: "Awaiting Submission", + viewKey: "awaitingSubmissionDetails", + }) + ); + } + + store.dispatch(setLoggedInUserId(loggedInUser)); + store.dispatch(setLoggedInUserEmail(loggedInUserEmail)); + store.dispatch(setAppealLPA(query.lpa)); + store.dispatch(setAppealTypeID(query.apt)); + store.dispatch(setCaseReferenceAction(caseReference)); + store.dispatch(setForm(xmlStr, mandatoryFieldsData, pickListData)); + store.dispatch(setAppealType(appealTypeData)); + store.dispatch(setContainerID(session.user.id)); + store.dispatch(setAccountDetails(accountDetails)); + + store.dispatch(setFilesForAppeal(blobList)); +} diff --git a/lib/myportal/loadMyPortalAppealPage.js b/lib/myportal/loadMyPortalAppealPage.js new file mode 100644 index 00000000..a1d321c8 --- /dev/null +++ b/lib/myportal/loadMyPortalAppealPage.js @@ -0,0 +1,91 @@ +// lib/myportal/loadMyPortalAppealPage.js +import { getSession } from "next-auth/react"; +import { + getAppealsTypesForNewAppeal, + getAwaitingSubmissionFromBlob, + getFilesFromBlob, + getIP, + getMandatoryFields, + getPickLists, + getProgressFromBlob, + getPersonalAccount, +} from "../../actions"; + +import { readFormXml } from "../forms/readFormXml"; +import { requireQueryParams } from "../routing/requireQueryParams"; + +/** + * Loader for "resume appeal" in /myportal/[appealtypes] + */ +export async function loadMyPortalAppealPage(ctx) { + const { query, req } = ctx; + + getIP(req); + + // Required params for resume flow (adjust if your routes always provide them) + // casereference is the main identifier here + const required = requireQueryParams(query, [ + "appealtypes", + "apt", + "casereference", + ]); + if (!required.ok) { + return { redirect: required.redirect }; + } + + const session = await getSession(ctx); + if (!session) { + return { + redirect: { + destination: "/auth/signin", + permanent: false, + }, + }; + } + + const { cookies } = req; + const loggedInUser = cookies?.pinsUser; + const loggedInUserIdent = session.user.id; + const loggedInUserEmail = session.user.email; + + const accountDetails = await getPersonalAccount(loggedInUser); + + // Fetch config + blob assets in parallel + const [appealTypeData, mandatoryFieldsData, pickListData, blobList] = + await Promise.all([ + getAppealsTypesForNewAppeal(), + getMandatoryFields(query.appealtypes), + getPickLists(query.appealtypes), + getFilesFromBlob(loggedInUserIdent, query.casereference), + ]); + + const blobProgress = await getProgressFromBlob( + loggedInUserIdent, + query.casereference + ); + + // Optional: awaiting-submission view setup when query.key exists + let awaitingSubmissionFromBlob = null; + if (Object.prototype.hasOwnProperty.call(query, "key")) { + awaitingSubmissionFromBlob = await getAwaitingSubmissionFromBlob( + session.user.id + ); + } + + const { xmlStr } = readFormXml(query.appealtypes); + + return { + session, + loggedInUser, + loggedInUserIdent, + loggedInUserEmail, + appealTypeData, + mandatoryFieldsData, + pickListData, + blobList, + blobProgress, + accountDetails, + awaitingSubmissionFromBlob, + xmlStr, + }; +} diff --git a/lib/newappeal/hydrateNewAppealStore.js b/lib/newappeal/hydrateNewAppealStore.js new file mode 100644 index 00000000..23ca1e43 --- /dev/null +++ b/lib/newappeal/hydrateNewAppealStore.js @@ -0,0 +1,48 @@ +// lib/newappeal/hydrateNewAppealStore.js +import { + setContainerID, + setLoggedInUserEmail, + setLoggedInUserId, + setAccountDetails, +} from "../../store/accountDetails/action"; +import { + setAppealLPA, + setAppealType, + setAppealTypeID, + // IMPORTANT: avoid name collision in your page by importing as Action + setCaseReference as setCaseReferenceAction, +} from "../../store/appealType/action"; +import { setForm } from "../../store/formData/action"; + +/** + * Dispatches all actions needed to hydrate Redux store for the page. + */ +export function hydrateNewAppealStore(store, query, data) { + const { + session, + loggedInUser, + loggedInUserEmail, + appealTypeData, + mandatoryFieldsData, + pickListData, + blobProgress, + accountDetails, + xmlStr, + } = data; + + const caseReference = { + ticketnumber: query.id, + incidentid: query.id, + caseDetails: blobProgress, + }; + + store.dispatch(setLoggedInUserId(loggedInUser)); + store.dispatch(setLoggedInUserEmail(loggedInUserEmail)); + store.dispatch(setAppealLPA(query.lpa)); + store.dispatch(setAppealTypeID(query.apt)); + store.dispatch(setCaseReferenceAction(caseReference)); + store.dispatch(setForm(xmlStr, mandatoryFieldsData, pickListData)); + store.dispatch(setAppealType(appealTypeData)); + store.dispatch(setContainerID(session.user.id)); + store.dispatch(setAccountDetails(accountDetails)); +} diff --git a/lib/newappeal/loadNewAppealPage.js b/lib/newappeal/loadNewAppealPage.js new file mode 100644 index 00000000..786e7c43 --- /dev/null +++ b/lib/newappeal/loadNewAppealPage.js @@ -0,0 +1,69 @@ +// lib/newappeal/loadNewAppealPage.js +import { getSession } from "next-auth/react"; +import { + getAppealsTypesForNewAppeal, + getIP, + getMandatoryFields, + getPickLists, + getProgressFromBlob, + getPersonalAccount, +} from "../../actions"; +import { readFormXml } from "../forms/readFormXml"; +import { requireQueryParams } from "../routing/requireQueryParams"; + +/** + * Loads everything needed for New Appeal SSR. + * Returns { redirect } on auth/query issues, otherwise returns a data object. + */ +export async function loadNewAppealPage(ctx) { + const { query, req } = ctx; + + // Preserve existing behaviour + getIP(req); + + // Validate required params early (adjust keys if needed) + const required = requireQueryParams(query, ["appealtypes", "apt", "id"]); + if (!required.ok) { + return { redirect: required.redirect }; + } + + const session = await getSession(ctx); + if (!session) { + return { + redirect: { + destination: "/auth/signin", + permanent: false, + }, + }; + } + + const { cookies } = req; + const loggedInUser = cookies?.pinsUser; // existing cookie usage + const loggedInUserIdent = session.user.id; + const loggedInUserEmail = session.user.email; + + const [appealTypeData, mandatoryFieldsData, pickListData] = + await Promise.all([ + getAppealsTypesForNewAppeal(), + getMandatoryFields(query.appealtypes), + getPickLists(query.appealtypes), + ]); + + const blobProgress = await getProgressFromBlob(loggedInUserIdent, query.id); + const accountDetails = await getPersonalAccount(loggedInUser); + + const { xmlStr } = readFormXml(query.appealtypes); + + return { + session, + loggedInUser, + loggedInUserIdent, + loggedInUserEmail, + appealTypeData, + mandatoryFieldsData, + pickListData, + blobProgress, + accountDetails, + xmlStr, + }; +} diff --git a/lib/routing/requireQueryParams.js b/lib/routing/requireQueryParams.js new file mode 100644 index 00000000..f8ede185 --- /dev/null +++ b/lib/routing/requireQueryParams.js @@ -0,0 +1,21 @@ +// lib/routing/requireQueryParams.js +// Simple query validator for getServerSideProps + +export function requireQueryParams(query, requiredKeys = []) { + const missing = requiredKeys.filter((k) => !query?.[k]); + if (missing.length === 0) return { ok: true }; + + // Redirect to a generic error page you already have + // (you can swap this destination later) + const destination = `/error?missing=${encodeURIComponent( + missing.join(",") + )}`; + return { + ok: false, + redirect: { + destination, + permanent: false, + }, + missing, + }; +} diff --git a/locales/cy/myrepresentations.json b/locales/cy/myrepresentations.json index 027f2b3a..c776853d 100644 --- a/locales/cy/myrepresentations.json +++ b/locales/cy/myrepresentations.json @@ -252,5 +252,7 @@ "rep-period-passed-heading": "Mae'r cyfnod cynrychioli wedi mynd heibio", "rep-period-notice-label": "Aeth y dyddiad dyledus ar gyfer y sylw hwn heibio. Ni allwch gyflwyno'r wybodaeth a ddarparwyd gennych mwyach.", "representation-onbehalfof-hint": " e.e. \"Perchnogion Rhifau 1-5 Stryd Fawr\", neu \"Mr a Mrs Smith\" neu \"ysgutorion ystâd Mr Evans\"", - "representation-onbehalfof-label": "Rhowch enw'r cwmni/grŵp/sefydliad" + "representation-onbehalfof-label": "Rhowch enw'r cwmni/grŵp/sefydliad", + "docsoffline-reps-label": "Oherwydd gwaith cynnal a chadw system, ni allwn dderbyn sylwadau ar hyn o bryd. Rhowch gynnig arall arni yn nes ymlaen.", + "return-to-myportal-link": "Dychwelyd i Fy Mhorth" } \ No newline at end of file diff --git a/locales/cy/newappeal.json b/locales/cy/newappeal.json index bd59bbd9..4ba06f38 100644 --- a/locales/cy/newappeal.json +++ b/locales/cy/newappeal.json @@ -120,5 +120,6 @@ "new-appeal-finalising-heading": "Cwblhau cyflwyniad eich apêl", "new-appeal-finalising-label": "Wrthi'n uwchlwytho ffeiliau ar hyn o bryd a chwblhau eich cyflwyniad apêl", "new-appeal-wait-label": "Arhoswch os gwelwch yn dda", - "invalid-email-address-errormsg": "Cyfeiriad e-bost annilys" + "invalid-email-address-errormsg": "Cyfeiriad e-bost annilys", + "return-to-myportal-link": "Dychwelyd i Fy Mhorth" } \ No newline at end of file diff --git a/locales/en/myrepresentations.json b/locales/en/myrepresentations.json index aaa4e53a..8618b50f 100644 --- a/locales/en/myrepresentations.json +++ b/locales/en/myrepresentations.json @@ -252,5 +252,7 @@ "rep-period-passed-heading": "Representation period has passed", "rep-period-notice-label": "The due date for this representation passed. You can no longer submit the information you have provided.", "representation-onbehalfof-hint": "e.g. \"Owners of Numbers 1-5 High Street\", or \"Mr and Mrs Smith\" or \"The executors of Mr Evans' estate\"", - "representation-onbehalfof-label": "Enter the name of the company/group/organisation" + "representation-onbehalfof-label": "Enter the name of the company/group/organisation", + "docsoffline-reps-label": "Due to system maintenance, we are unable to accept representations at this time. Please try again later.", + "return-to-myportal-link": "Return to My Portal" } \ No newline at end of file diff --git a/locales/en/newappeal.json b/locales/en/newappeal.json index 8580faf2..6414ee36 100644 --- a/locales/en/newappeal.json +++ b/locales/en/newappeal.json @@ -120,5 +120,6 @@ "new-appeal-finalising-heading": "Finalising your appeal submission", "new-appeal-finalising-label": "Currently uploading files and finalising your appeal submission", "new-appeal-wait-label": "Please wait", - "invalid-email-address-errormsg": "Invalid email address" + "invalid-email-address-errormsg": "Invalid email address", + "return-to-myportal-link": "Return to My Portal" } \ No newline at end of file diff --git a/pages/myportal/[appealtypes].js b/pages/myportal/[appealtypes].js index 950c7e41..62f3631d 100644 --- a/pages/myportal/[appealtypes].js +++ b/pages/myportal/[appealtypes].js @@ -1,345 +1,465 @@ -import fs from "fs"; -import { JSONPath as jsonpath } from "jsonpath-plus"; -import useTranslation from "next-translate/useTranslation"; -import Head from "next/head"; -import { useRouter } from "next/router"; -import { useEffect } from "react"; -import { connect } from "react-redux"; -import xpath from "xpath"; -import { - getAppealsTypesForNewAppeal, - getAwaitingSubmissionFromBlob, - getFilesFromBlob, - getIP, - getMandatoryFields, - getPickLists, - getProgressFromBlob, - getPersonalAccount, -} from "../../actions"; -import Breadcrumbs from "../../components/breadcrumbs"; -import CookieBanner from "../../components/cookieBanner"; -import Footer from "../../components/footer"; -import Header from "../../components/header"; -import BuildCheckSection from "../../components/newappeal/buildchecksection"; -import BuildSection from "../../components/newappeal/buildsection"; -import CompleteAppeal from "../../components/newappeal/complete"; -import TimeOut from "../../components/timeout"; +// import fs from "fs"; +// import { JSONPath as jsonpath } from "jsonpath-plus"; +// import useTranslation from "next-translate/useTranslation"; +// import Head from "next/head"; +// import { useRouter } from "next/router"; +// import { useEffect } from "react"; +// import { connect } from "react-redux"; +// import xpath from "xpath"; +// import { +// getAppealsTypesForNewAppeal, +// getAwaitingSubmissionFromBlob, +// getFilesFromBlob, +// getIP, +// getMandatoryFields, +// getPickLists, +// getProgressFromBlob, +// getPersonalAccount, +// } from "../../actions"; +// import Breadcrumbs from "../../components/breadcrumbs"; +// import CookieBanner from "../../components/cookieBanner"; +// import Footer from "../../components/footer"; +// import Header from "../../components/header"; +// import BuildCheckSection from "../../components/newappeal/buildchecksection"; +// import BuildSection from "../../components/newappeal/buildsection"; +// import CompleteAppeal from "../../components/newappeal/complete"; +// import TimeOut from "../../components/timeout"; + +// import { getSession } from "next-auth/react"; +// import { +// setContainerID, +// setLoggedInUserEmail, +// setLoggedInUserId, +// setAccountDetails, +// } from "../../store/accountDetails/action"; +// import { +// setAppealLPA, +// setAppealType, +// setAppealTypeID, +// setAppealTypeTitle, +// setCaseReference, +// setFilesForAppeal, +// } from "../../store/appealType/action"; +// import { +// setAwaitingSubmissionDetails, +// setAwaitingSubmissionFromBlob, +// } from "../../store/awaitingSubmission/action"; +// import { setCurrentView, setLocale } from "../../store/currentView/action"; +// import { setForm } from "../../store/formData/action"; +// import { wrapper } from "../../store/store"; +// import ServiceBanner from "../../components/myportal/servicebanner"; + +// let Home = (props) => { +// const { footerLinks, pages, formData } = props; +// let { t, lang } = useTranslation(); + +// const router = useRouter(); +// const { locale } = router; +// const { appealtypes } = router.query; + +// useEffect(() => { +// //setFormTitle(formTitle); +// setCaseReference(router.query.casereference); +// }, []); // eslint-disable-line react-hooks/exhaustive-deps + +// const formXML = props.formData.formData; +// const parser = new DOMParser(); +// var doc = parser.parseFromString(formXML, "text/xml"); +// var titles = xpath.select( +// "//form/tabs/tab[*]/labels/label[@description]/@description", +// doc +// ); +// var sectionCount = xpath.select("/form/tabs/tab[*]", doc); +// sectionCount = sectionCount.length; + +// var tabs = xpath.select("//form/tabs/tab[*]", doc); + +// let optionsStr = props.appealType.appealTypeOptions.value || {}; + +// let selectedObj = jsonpath({ +// path: "$..[?(@ && @.attributevalue=='" + router.query.apt + "')]", +// json: optionsStr, +// eval: true, +// }); + +// //let optionsTitleObj = []; + +// //const optionsTitleObj = selectedObj.reduce( +// // (obj, arrValue) => ( +// // (obj[arrValue] = arrValue +// // .replace(/(\band|[\s\-\+\(\)\,\&])/g, "") +// // .toLowerCase() +// // .slice(0, 39)), +// // obj +// // ), +// // {} +// // ); + +// const formTitle = selectedObj[0].value; + +// const { onSubmit } = props; + +// return ( +//
    +// +// +// {t("newappeal:page-title")} - {t("common:service-name")} +// +// <> +// +// +// {/* If they have a Twitter Handle, include the meta details below */} +// +// + +// +// +// +// +// +// +// +// +// +// +// +// +// +//
    +// +//
    + +//
    +// +// +//
    +// {props.appealType.currentSection == 9999 ? ( +// +// ) : props.appealType.currentSection == +// sectionCount + 1 ? ( +// +// ) : ( +// <> +// +// +// )} +//
    +//
    +//
    +//
    +// +//
    +// ); +// }; + +// export const getServerSideProps = wrapper.getServerSideProps( +// (store) => async (ctx) => { +// const { query, req, res } = ctx; +// getIP(req); +// const { cookies } = req; + +// console.log("the query", query); +// let loggedInUser = cookies.pinsUser; + +// let thisSession = await getSession(ctx); + +// if (!thisSession) { +// console.log("not has sesssion......."); +// return { +// redirect: { +// destination: "/auth/signin", +// permanent: false, +// }, +// }; +// } + +// console.log(ctx.locale); +// store.dispatch(setLocale(ctx.locale)); + +// let loggedInUserIdent = thisSession.user.id; +// let loggedInUserEmail = thisSession.user.email; + +// //console.log("logged ident:", loggedInUserIdent); + +// console.log("which appeal: ", query.appealtypes); + +// const accountDetails = await getPersonalAccount(loggedInUser); + +// const [appealTypeData, mandatoryFieldsData, pickListData, blobList] = +// await Promise.all([ +// await getAppealsTypesForNewAppeal(), +// await getMandatoryFields(query.appealtypes), +// await getPickLists(query.appealtypes), +// await getFilesFromBlob(loggedInUserIdent, query.casereference), +// ]); + +// const blobProgress = await getProgressFromBlob( +// loggedInUserIdent, +// query.casereference +// ); + +// //console.log("/////////\nappeal type data:", appealTypeData); + +// // +// // Removed to make progress from Blob not CRM +// // + +// // let searchResultsObj = await getPartSavedAppeal(query.casereference); +// // //console.log("eeee:", searchResultsObj); +// // let searchDetailsObj = await getPartSavedDetails(searchResultsObj); + +// // searchDetailsObj = searchDetailsObj[0].value[0]; + +// // Object.keys(searchDetailsObj).forEach((key) => { +// // if (searchDetailsObj[key] === null) { +// // delete searchDetailsObj[key]; +// // } +// // }); + +// //console.log("appeal:", searchDetailsObj); + +// // searchDetailsObj = JSON.stringify(searchDetailsObj); +// // searchDetailsObj = searchDetailsObj.replace(/:true/gm, `:"Yes"`); +// // searchDetailsObj = searchDetailsObj.replace(/:false/gm, `:"No"`); +// // searchDetailsObj = JSON.parse(searchDetailsObj); + +// let caseReference = {}; + +// caseReference.ticketnumber = query.casereference; +// caseReference.incidentid = query.inid; +// caseReference.caseDetails = blobProgress; //searchDetailsObj; + +// var path = require("path"); +// const configDirectory = path.resolve(process.cwd(), "data/formsxml"); +// var xmlStr = fs.readFileSync( +// path.join(configDirectory, query.appealtypes + ".xml"), +// "utf8" +// ); + +// xmlStr = xmlStr.replace(/\t/g, ""); +// xmlStr = xmlStr.replace(/\n/g, ""); +// xmlStr = xmlStr.replace(/> <"/g, "><"); +// xmlStr = xmlStr.toString(); + +// if (query.hasOwnProperty("key")) { +// const awaitingSubmissionFromBlob = +// await getAwaitingSubmissionFromBlob(thisSession.user.id); + +// store.dispatch( +// setAwaitingSubmissionFromBlob(awaitingSubmissionFromBlob) +// ); + +// store.dispatch( +// setAwaitingSubmissionDetails(awaitingSubmissionFromBlob) +// ); +// store.dispatch( +// setCurrentView({ +// "viewName": "Awaiting Submission", +// "viewKey": "awaitingSubmissionDetails", +// }) +// ); +// } + +// store.dispatch(setLoggedInUserId(loggedInUser)); +// store.dispatch(setLoggedInUserEmail(loggedInUserEmail)); +// store.dispatch(setAppealLPA(query.lpa)); +// store.dispatch(setAppealTypeID(query.apt)); +// store.dispatch(setCaseReference(caseReference)); +// store.dispatch(setForm(xmlStr, mandatoryFieldsData, pickListData)); +// store.dispatch(setAppealType(appealTypeData)); +// store.dispatch(setContainerID(thisSession.user.id)); +// store.dispatch(setAccountDetails(accountDetails)); + +// store.dispatch(setFilesForAppeal(blobList)); + +// return { +// props: { url: process.env.NEXTAUTH_URL }, +// }; +// } +// ); + +// const mapStateToProps = (state) => { +// return { +// search: state.search, +// searchResultsObj: state.searchResultsObj, +// formData: state.formData, +// appealType: state.appealType, +// form: state.form, +// accountDetails: state.accountDetails, +// awaitingSubmission: state.awaitingSubmission, +// currentView: state.currentView, +// initialValues: state.appealType.caseReference.caseDetails, +// }; +// }; + +// const mapDispatchToProps = (dispatch) => { +// return { +// setFormTitle: (title) => { +// dispatch(setAppealTypeTitle(title)); +// }, +// setCaseReference: (refno) => { +// dispatch(setCaseReference(refno)); +// }, +// setFilesForAppeal: (blobList) => { +// dispatch(setFilesForAppeal(blobList)); +// }, +// }; +// }; + +// export default connect(mapStateToProps, mapDispatchToProps)(Home); + +// pages/myportal/[appealtypes].js +import { JSONPath as jsonpath } from "jsonpath-plus"; +import xpath from "xpath"; +import { useMemo } from "react"; +import { connect } from "react-redux"; +import { useRouter } from "next/router"; -import { getSession } from "next-auth/react"; -import { - setContainerID, - setLoggedInUserEmail, - setLoggedInUserId, - setAccountDetails, -} from "../../store/accountDetails/action"; -import { - setAppealLPA, - setAppealType, - setAppealTypeID, - setAppealTypeTitle, - setCaseReference, - setFilesForAppeal, -} from "../../store/appealType/action"; -import { - setAwaitingSubmissionDetails, - setAwaitingSubmissionFromBlob, -} from "../../store/awaitingSubmission/action"; -import { setCurrentView, setLocale } from "../../store/currentView/action"; -import { setForm } from "../../store/formData/action"; import { wrapper } from "../../store/store"; -import ServiceBanner from "../../components/myportal/servicebanner"; + +import NewAppealPageShell from "../../components/newappeal/newAppealPageShell"; +import NewAppealFlow from "../../components/newappeal/newAppealFlow"; + +import { loadMyPortalAppealPage } from "../../lib/myportal/loadMyPortalAppealPage"; +import { hydrateMyPortalAppealStore } from "../../lib/myportal/hydrateMyPortalAppealStore"; let Home = (props) => { - const { footerLinks, pages, formData } = props; - let { t, lang } = useTranslation(); - const router = useRouter(); - const { locale } = router; const { appealtypes } = router.query; - useEffect(() => { - //setFormTitle(formTitle); - setCaseReference(router.query.casereference); - }, []); // eslint-disable-line react-hooks/exhaustive-deps + const formXML = props.formData?.formData; - const formXML = props.formData.formData; - const parser = new DOMParser(); - var doc = parser.parseFromString(formXML, "text/xml"); - var titles = xpath.select( - "//form/tabs/tab[*]/labels/label[@description]/@description", - doc - ); - var sectionCount = xpath.select("/form/tabs/tab[*]", doc); - sectionCount = sectionCount.length; + // Memoise XML parsing + const { sectionCount } = useMemo(() => { + if (!formXML) return { sectionCount: 0 }; + const parser = new DOMParser(); + const doc = parser.parseFromString(formXML, "text/xml"); + const count = xpath.select("/form/tabs/tab[*]", doc)?.length || 0; + return { sectionCount: count }; + }, [formXML]); - var tabs = xpath.select("//form/tabs/tab[*]", doc); + // Safe formTitle resolution + const formTitle = useMemo(() => { + const optionsStr = props.appealType?.appealTypeOptions?.value; + const apt = router.query.apt; - let optionsStr = props.appealType.appealTypeOptions.value || {}; + if (!optionsStr || !apt) return "New appeal"; - let selectedObj = jsonpath({ - path: "$..[?(@ && @.attributevalue=='" + router.query.apt + "')]", - json: optionsStr, - eval: true, - }); + const selectedObj = jsonpath({ + path: "$..[?(@ && @.attributevalue=='" + apt + "')]", + json: optionsStr, + eval: true, + }); - //let optionsTitleObj = []; - - //const optionsTitleObj = selectedObj.reduce( - // (obj, arrValue) => ( - // (obj[arrValue] = arrValue - // .replace(/(\band|[\s\-\+\(\)\,\&])/g, "") - // .toLowerCase() - // .slice(0, 39)), - // obj - // ), - // {} - // ); - - const formTitle = selectedObj[0].value; + return selectedObj?.[0]?.value || "New appeal"; + }, [props.appealType?.appealTypeOptions?.value, router.query.apt]); + const { footerLinks } = props; const { onSubmit } = props; return ( -
    - - - {t("newappeal:page-title")} - {t("common:service-name")} - - <> - - - {/* If they have a Twitter Handle, include the meta details below */} - - - - - - - - - - - - - - - - -
    - -
    - -
    - - -
    - {props.appealType.currentSection == 9999 ? ( - - ) : props.appealType.currentSection == - sectionCount + 1 ? ( - - ) : ( - <> - - - )} -
    -
    -
    -
    - -
    + + + ); }; export const getServerSideProps = wrapper.getServerSideProps( (store) => async (ctx) => { - const { query, req, res } = ctx; - getIP(req); - const { cookies } = req; + const result = await loadMyPortalAppealPage(ctx); - console.log("the query", query); - let loggedInUser = cookies.pinsUser; - - let thisSession = await getSession(ctx); - - if (!thisSession) { - console.log("not has sesssion......."); - return { - redirect: { - destination: "/auth/signin", - permanent: false, - }, - }; + if (result?.redirect) { + return { redirect: result.redirect }; } - console.log(ctx.locale); - store.dispatch(setLocale(ctx.locale)); - - let loggedInUserIdent = thisSession.user.id; - let loggedInUserEmail = thisSession.user.email; - - //console.log("logged ident:", loggedInUserIdent); - - console.log("which appeal: ", query.appealtypes); - - const accountDetails = await getPersonalAccount(loggedInUser); - - const [appealTypeData, mandatoryFieldsData, pickListData, blobList] = - await Promise.all([ - await getAppealsTypesForNewAppeal(), - await getMandatoryFields(query.appealtypes), - await getPickLists(query.appealtypes), - await getFilesFromBlob(loggedInUserIdent, query.casereference), - ]); - - const blobProgress = await getProgressFromBlob( - loggedInUserIdent, - query.casereference - ); - - //console.log("/////////\nappeal type data:", appealTypeData); - - // - // Removed to make progress from Blob not CRM - // - - // let searchResultsObj = await getPartSavedAppeal(query.casereference); - // //console.log("eeee:", searchResultsObj); - // let searchDetailsObj = await getPartSavedDetails(searchResultsObj); - - // searchDetailsObj = searchDetailsObj[0].value[0]; - - // Object.keys(searchDetailsObj).forEach((key) => { - // if (searchDetailsObj[key] === null) { - // delete searchDetailsObj[key]; - // } - // }); - - //console.log("appeal:", searchDetailsObj); - - // searchDetailsObj = JSON.stringify(searchDetailsObj); - // searchDetailsObj = searchDetailsObj.replace(/:true/gm, `:"Yes"`); - // searchDetailsObj = searchDetailsObj.replace(/:false/gm, `:"No"`); - // searchDetailsObj = JSON.parse(searchDetailsObj); - - let caseReference = {}; - - caseReference.ticketnumber = query.casereference; - caseReference.incidentid = query.inid; - caseReference.caseDetails = blobProgress; //searchDetailsObj; - - var path = require("path"); - const configDirectory = path.resolve(process.cwd(), "data/formsxml"); - var xmlStr = fs.readFileSync( - path.join(configDirectory, query.appealtypes + ".xml"), - "utf8" - ); - - xmlStr = xmlStr.replace(/\t/g, ""); - xmlStr = xmlStr.replace(/\n/g, ""); - xmlStr = xmlStr.replace(/> <"/g, "><"); - xmlStr = xmlStr.toString(); - - if (query.hasOwnProperty("key")) { - const awaitingSubmissionFromBlob = - await getAwaitingSubmissionFromBlob(thisSession.user.id); - - store.dispatch( - setAwaitingSubmissionFromBlob(awaitingSubmissionFromBlob) - ); - - store.dispatch( - setAwaitingSubmissionDetails(awaitingSubmissionFromBlob) - ); - store.dispatch( - setCurrentView({ - "viewName": "Awaiting Submission", - "viewKey": "awaitingSubmissionDetails", - }) - ); - } - - store.dispatch(setLoggedInUserId(loggedInUser)); - store.dispatch(setLoggedInUserEmail(loggedInUserEmail)); - store.dispatch(setAppealLPA(query.lpa)); - store.dispatch(setAppealTypeID(query.apt)); - store.dispatch(setCaseReference(caseReference)); - store.dispatch(setForm(xmlStr, mandatoryFieldsData, pickListData)); - store.dispatch(setAppealType(appealTypeData)); - store.dispatch(setContainerID(thisSession.user.id)); - store.dispatch(setAccountDetails(accountDetails)); - - store.dispatch(setFilesForAppeal(blobList)); + hydrateMyPortalAppealStore(store, ctx, result); return { - props: { url: process.env.NEXTAUTH_URL }, + props: { + url: process.env.NEXTAUTH_URL, + docsOffline: process.env.DOCAPI_OFFLINE || false, + }, }; } ); @@ -354,21 +474,14 @@ const mapStateToProps = (state) => { accountDetails: state.accountDetails, awaitingSubmission: state.awaitingSubmission, currentView: state.currentView, - initialValues: state.appealType.caseReference.caseDetails, + initialValues: state.appealType.caseReference?.caseDetails, }; }; const mapDispatchToProps = (dispatch) => { return { - setFormTitle: (title) => { - dispatch(setAppealTypeTitle(title)); - }, - setCaseReference: (refno) => { - dispatch(setCaseReference(refno)); - }, - setFilesForAppeal: (blobList) => { - dispatch(setFilesForAppeal(blobList)); - }, + // Keep these only if something else uses them; + // this page no longer needs the useEffect that called setCaseReference. }; }; diff --git a/pages/myportal/representation.js b/pages/myportal/representation.js index de7bce6e..f8b3a726 100644 --- a/pages/myportal/representation.js +++ b/pages/myportal/representation.js @@ -209,6 +209,7 @@ const RepresentationF = (props) => { } setCurrentReference={setCurrentReference} showQuestionnaireSection={showQuestionnaireSection} + docsOffline={props.docsOffline} />