fix for pdf formatting and hyperlinks

This commit is contained in:
2026-03-09 13:11:28 +00:00
parent 95c1492fe0
commit 96e180040d
4 changed files with 241 additions and 221 deletions
+115 -114
View File
@@ -5,7 +5,7 @@ import {
getBasicSearchDetails,
getBasicSearchDetailsPaged,
getPortalModuleDetailsProxy,
getPortalModuleDetails,
getPortalModuleDetails
} from "../../actions";
import data from "../../data/collections.json";
import { useRouter } from "next/router";
@@ -20,7 +20,7 @@ export const getFormCollection = (formtype) => {
const collectionName = jsonpath({
path: "$..[?(@ && @.LogicalName=='" + formtype + "')]",
json: data,
eval: true,
eval: true
});
return collectionName[0];
};
@@ -29,7 +29,7 @@ export const getFormCollectionByID = (appealTypeID) => {
const collectionName = jsonpath({
path: "$..[?(@ && @.appealTypeID =='" + appealTypeID + "')]",
json: data,
eval: true,
eval: true
});
return collectionName[0];
};
@@ -38,7 +38,7 @@ export const getNavigationPropertyByPrimaryAttribute = (primaryAttribute) => {
const collectionName = jsonpath({
path: "$..[?(@ && @.PrimaryIdAttribute =='" + primaryAttribute + "')]",
json: data,
eval: true,
eval: true
});
return collectionName[0];
};
@@ -47,7 +47,7 @@ export const getFormIDByLogicalName = (appealTypeLogicalName) => {
const collectionName = jsonpath({
path: "$..[?(@ && @.LogicalName =='" + appealTypeLogicalName + "')]",
json: data,
eval: true,
eval: true
});
return collectionName[0];
};
@@ -56,7 +56,7 @@ export const getPickListLabel = (data, picklistType, picklistID) => {
const pickListData = jsonpath({
path: "$..[?(@ && @.LogicalName=='" + picklistType + "')]",
json: data,
eval: true,
eval: true
});
const pickListLabel = jsonpath({
@@ -66,7 +66,7 @@ export const getPickListLabel = (data, picklistType, picklistID) => {
"')].Label.LocalizedLabels..Label",
json: pickListData,
eval: true,
eval: true
});
return pickListLabel[0];
};
@@ -75,7 +75,7 @@ export const getRadioLabel = (data, radiotListName, radioListID) => {
const radioListData = jsonpath({
path: "$..[?(@ && @.LogicalName=='" + radiotListName + "')]",
json: data,
eval: true,
eval: true
});
const pickListLabel = jsonpath({
@@ -85,7 +85,7 @@ export const getRadioLabel = (data, radiotListName, radioListID) => {
"')].Label.LocalizedLabels..Label",
json: radioListData,
eval: true,
eval: true
});
return pickListLabel[0];
};
@@ -100,7 +100,7 @@ export const getSearchDetails = async (searchResultsObj) => {
searchResultsObj = searchResultsObj.value;
const detailsObj = searchResultsObj.map((searchDetail, index) => {
let formMeta = getFormCollectionByID(
searchDetail.pinswg_appealcasetype,
searchDetail.pinswg_appealcasetype
);
// console.log(
// "------------------- Details: ",
@@ -117,11 +117,11 @@ export const getSearchDetails = async (searchResultsObj) => {
"pinswg_dnses",
searchDetail.title,
"pinswg_dnsid",
searchDetail.incidentid,
searchDetail.incidentid
) || {
"@odata.count": 1,
"value": [{ "title": searchDetail.title }],
},
"value": [{ "title": searchDetail.title }]
}
);
} else {
// formMeta?.LogicalCollectionName &&
@@ -131,11 +131,11 @@ export const getSearchDetails = async (searchResultsObj) => {
formMeta.LogicalCollectionName,
searchDetail.title,
formMeta.PrimaryIdAttribute,
searchDetail.incidentid,
searchDetail.incidentid
) || {
"@odata.count": 1,
"value": [{ "title": searchDetail.title }],
},
"value": [{ "title": searchDetail.title }]
}
);
}
});
@@ -159,7 +159,7 @@ export const getPartSavedDetails = (searchResultsObj) => {
console.log(searchDetail.title);
} else {
let formMeta = getFormCollectionByID(
searchDetail.pinswg_appealcasetype,
searchDetail.pinswg_appealcasetype
);
// console.log(formMeta);
detailsArr.push(
@@ -167,8 +167,8 @@ export const getPartSavedDetails = (searchResultsObj) => {
formMeta.LogicalCollectionName,
searchDetail.title,
formMeta.PrimaryIdAttribute,
searchDetail.incidentid,
),
searchDetail.incidentid
)
);
}
});
@@ -279,7 +279,7 @@ export const getSearchDetailsPaged = async (searchResultsObj) => {
if (!acc[appealType]) acc[appealType] = [];
acc[appealType].push({
incidentID: detail.incidentid,
title: detail.title,
title: detail.title
});
return acc;
}, {});
@@ -307,7 +307,7 @@ export const getSearchDetailsPaged = async (searchResultsObj) => {
formMeta.LogicalCollectionName, // appealTypeName
null, // caseReference is no longer used in batch
formMeta.PrimaryIdAttribute, // primaryIdAttribute
incidentIDs, // pass array of incidentIDs
incidentIDs // pass array of incidentIDs
);
allDetails.push(...details);
@@ -323,7 +323,7 @@ export const getProgressObj = (
formObjXML,
titleList,
mandatoryFieldsData,
props,
props
) => {
const parser = new DOMParser();
const BuildFormObj = (formObjXML) => {
@@ -336,7 +336,7 @@ export const getProgressObj = (
"//tabs/tab[" +
(index + 1) +
"]//rows/row/control[not(@parentField)]/..",
doc,
doc
);
return BuildRowObj(sectionXML, titleList[key].value);
@@ -376,10 +376,10 @@ export const getProgressObj = (
0) ||
(_.has(props.props.form.appealForm, "values") &&
Object.keys(
props.props.form.appealForm.values,
props.props.form.appealForm.values
).filter((k) => k.startsWith("pinswg_fileUpload"))
.length > 0)
: rowCount == formObj[key].fieldsTotal,
: rowCount == formObj[key].fieldsTotal
};
});
@@ -401,17 +401,17 @@ export const getProgressObj = (
var parentFieldShowOnValue = xpath.select(
"//@parentFieldShowOnValue",
doc,
doc
);
var requiredDocumentValue = xpath.select(
"//@requiredDocumentValue",
doc,
doc
);
var requiredDocumentLabel = xpath.select(
"//@requiredDocumentLabel",
doc,
doc
);
var hint = xpath.select("//label/@hint", doc);
@@ -449,7 +449,7 @@ export const getProgressObj = (
datafieldname[0].value +
"')]",
json: mandatoryFieldsData,
eval: true,
eval: true
});
if (datafieldname[0].value.includes("pinswg_fileUpload")) {
@@ -461,7 +461,7 @@ export const getProgressObj = (
"label": rows[0].value,
"datafieldname": datafieldname[0].value,
"datafieldcontent": datafieldcontent,
"validation": validation,
"validation": validation
};
}
} else {
@@ -471,7 +471,7 @@ export const getProgressObj = (
"datafieldname": datafieldname[0].value,
"key": key,
"picklistData": props.props.formData.pickListData,
"mandatoryFieldsData": mandatoryFieldsData,
"mandatoryFieldsData": mandatoryFieldsData
};
}
} else {
@@ -483,7 +483,7 @@ export const getProgressObj = (
"label": rows[0].value,
"datafieldname": datafieldname[0].value,
"datafieldcontent": datafieldcontent,
"validation": validation,
"validation": validation
};
} else {
return null;
@@ -518,7 +518,7 @@ export const getProgressObj = (
"title": titleList,
"validationFieldsTotal": filterUnwanted(rowObj).length,
"fieldsTotal": rowObj.length,
"fieldsrowObj": rowObj,
"fieldsrowObj": rowObj
};
};
@@ -616,7 +616,7 @@ export const getDetailsProxy = (resultsObj, detailsType) => {
? searchDetail.ticketnumber
: searchDetail[
"_pinswg_watchedcase_value@OData.Community.Display.V1.FormattedValue"
],
]
);
} else {
detailsArr.push(
@@ -627,8 +627,8 @@ export const getDetailsProxy = (resultsObj, detailsType) => {
? searchDetail.ticketnumber
: searchDetail[
"_pinswg_watchedcase_value@OData.Community.Display.V1.FormattedValue"
],
),
]
)
);
}
});
@@ -678,98 +678,99 @@ export const getDocumentTypeFromFilename = (filename) => {
return doctypeCode;
};
export const updateLinks = (jsonObj) => {
const parser = new DOMParser();
export const updateLinks = (input) => {
const EMPTY_QUILL_PARAGRAPHS_REGEX =
/<p[^>]*>\s*(?:<br\s*\/?>|&nbsp;|\s)*\s*<\/p>/gi;
// Function to process the HTML string and replace URLs with <a> tags
const processHtmlString = (htmlString) => {
const doc = parser.parseFromString(htmlString, "text/html");
const URL_REGEX = /\b(https?:\/\/[^\s<]+)/gi;
// Find all text nodes in the document
const walk = (node) => {
if (node.nodeType === Node.TEXT_NODE) {
const urlRegex =
/(?:https?:\/\/)?(?:www\.)?([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})(\/[^\s]*)?/g;
let match;
let currentText = node.textContent;
let lastIndex = 0;
let newNodeContent = [];
const stripTrailingUrlPunctuation = (url) => {
let cleanUrl = url;
let trailing = "";
// Process all URLs found in the current text node
while ((match = urlRegex.exec(currentText)) !== null) {
// Before the URL
if (match.index > lastIndex) {
newNodeContent.push(
currentText.slice(lastIndex, match.index),
);
while (/[.,!?;:'"]$/.test(cleanUrl)) {
trailing = cleanUrl.slice(-1) + trailing;
cleanUrl = cleanUrl.slice(0, -1);
}
const pairs = [
[")", "("],
["]", "["],
["}", "{"]
];
let changed = true;
while (changed && cleanUrl) {
changed = false;
for (const [close, open] of pairs) {
if (cleanUrl.endsWith(close)) {
const openCount = (
cleanUrl.match(new RegExp(`\\${open}`, "g")) || []
).length;
const closeCount = (
cleanUrl.match(new RegExp(`\\${close}`, "g")) || []
).length;
if (closeCount > openCount) {
trailing = close + trailing;
cleanUrl = cleanUrl.slice(0, -1);
changed = true;
}
// Construct the full URL (default to https://)
let fullUrl = match[0];
if (
!fullUrl.startsWith("http://") &&
!fullUrl.startsWith("https://")
) {
fullUrl = `https://${match[1]}${match[2] || ""}`; // Default to https
}
// Create the anchor element
const anchor = document.createElement("a");
anchor.href = fullUrl;
anchor.textContent = match[0];
anchor.target = "_blank";
anchor.setAttribute("rel", "noopener noreferrer");
// Add the anchor tag to the node content
newNodeContent.push(anchor);
// Update the last index processed
lastIndex = urlRegex.lastIndex;
}
// Add the remaining text after the last URL
if (lastIndex < currentText.length) {
newNodeContent.push(currentText.slice(lastIndex));
}
// If there were any replacements, update the text node
if (newNodeContent.length > 0) {
const fragment = document.createDocumentFragment();
newNodeContent.forEach((item) => {
if (typeof item === "string") {
fragment.appendChild(document.createTextNode(item));
} else {
fragment.appendChild(item);
}
});
node.parentNode.replaceChild(fragment, node);
}
}
}
// Traverse child nodes
for (let i = 0; i < node.childNodes.length; i++) {
walk(node.childNodes[i]);
}
};
walk(doc.body);
return doc.body.innerHTML;
return { cleanUrl, trailing };
};
// Iterate over the JSON object and process values that are strings (HTML content)
for (const key in jsonObj) {
if (jsonObj.hasOwnProperty(key)) {
const value = jsonObj[key];
const processHtmlString = (htmlString) => {
if (typeof htmlString !== "string" || !htmlString) return htmlString;
// If the value is a string and contains HTML, process it
if (typeof value === "string" && /<[^>]*>/g.test(value)) {
jsonObj[key] = processHtmlString(value);
let html = htmlString.replace(EMPTY_QUILL_PARAGRAPHS_REGEX, "");
const anchorPlaceholders = [];
html = html.replace(/<a\b[^>]*>[\s\S]*?<\/a>/gi, (match) => {
const token = `__ANCHOR_PLACEHOLDER_${anchorPlaceholders.length}__`;
anchorPlaceholders.push(match);
return token;
});
html = html.replace(URL_REGEX, (match) => {
const { cleanUrl, trailing } = stripTrailingUrlPunctuation(match);
if (!cleanUrl) return match;
return `<a href="${cleanUrl}" target="_blank" rel="noopener noreferrer">${cleanUrl}</a>${trailing}`;
});
html = html.replace(/__ANCHOR_PLACEHOLDER_(\d+)__/g, (_, index) => {
return anchorPlaceholders[Number(index)];
});
return html;
};
if (typeof input === "string") {
return processHtmlString(input);
}
if (!input || typeof input !== "object" || Array.isArray(input)) {
return input;
}
const updated = { ...input };
for (const key in updated) {
if (Object.prototype.hasOwnProperty.call(updated, key)) {
const value = updated[key];
if (typeof value === "string") {
updated[key] = processHtmlString(value);
}
}
}
return jsonObj;
return updated;
};
export const whichRepType = (props) => {