import { JSONPath as jsonpath } from "jsonpath-plus"; import { v4 as uuidv4 } from "uuid"; import { getBasicPartSavedDetails, getBasicSearchDetails, getBasicSearchDetailsPaged } from "../../actions/services/searchService"; import { getPortalModuleDetailsProxy, getPortalModuleDetails } from "../../actions/services/caseService"; import data from "../../data/collections.json"; import xpath from "xpath"; /* * Get the lookup collection by the appeal type entity * @param String formtype - string from appeal entity name */ export const getFormCollection = (formtype) => { const collectionName = jsonpath({ path: "$..[?(@ && @.LogicalName=='" + formtype + "')]", json: data, eval: true }); return collectionName[0]; }; export const getFormCollectionByID = (appealTypeID) => { const collectionName = jsonpath({ path: "$..[?(@ && @.appealTypeID =='" + appealTypeID + "')]", json: data, eval: true }); return collectionName[0]; }; export const getNavigationPropertyByPrimaryAttribute = (primaryAttribute) => { const collectionName = jsonpath({ path: "$..[?(@ && @.PrimaryIdAttribute =='" + primaryAttribute + "')]", json: data, eval: true }); return collectionName[0]; }; export const getFormIDByLogicalName = (appealTypeLogicalName) => { const collectionName = jsonpath({ path: "$..[?(@ && @.LogicalName =='" + appealTypeLogicalName + "')]", json: data, eval: true }); return collectionName[0]; }; export const getPickListLabel = (data, picklistType, picklistID) => { const pickListData = jsonpath({ path: "$..[?(@ && @.LogicalName=='" + picklistType + "')]", json: data, eval: true }); const pickListLabel = jsonpath({ path: "$..[?(@ && @.Value=='" + picklistID + "')].Label.LocalizedLabels..Label", json: pickListData, eval: true }); return pickListLabel[0]; }; export const getRadioLabel = (data, radiotListName, radioListID) => { const radioListData = jsonpath({ path: "$..[?(@ && @.LogicalName=='" + radiotListName + "')]", json: data, eval: true }); const pickListLabel = jsonpath({ path: "$..[?(@ && @.Value=='" + radioListID + "')].Label.LocalizedLabels..Label", json: radioListData, eval: true }); return pickListLabel[0]; }; /* * Get the details of a case from the appeal type * @param object searchResultsObj */ export const getSearchDetails = async (searchResultsObj) => { let detailsArr = []; searchResultsObj = searchResultsObj.value; const detailsObj = searchResultsObj.map((searchDetail, index) => { let formMeta = getFormCollectionByID( searchDetail.pinswg_appealcasetype ); // console.log( // "------------------- Details: ", // formMeta.LogicalCollectionName, // searchDetail.title, // formMeta.PrimaryIdAttribute, // searchDetail.incidentid, // searchDetail.pinswg_appealcasetype // ); if (searchDetail.pinswg_appealcasetype == null) { detailsArr.push( getBasicSearchDetails( "pinswg_dnses", searchDetail.title, "pinswg_dnsid", searchDetail.incidentid ) || { "@odata.count": 1, "value": [{ "title": searchDetail.title }] } ); } else { // formMeta?.LogicalCollectionName && // formMeta?.LogicalCollectionName != "pinswg_sipses" && detailsArr.push( getBasicSearchDetails( formMeta.LogicalCollectionName, searchDetail.title, formMeta.PrimaryIdAttribute, searchDetail.incidentid ) || { "@odata.count": 1, "value": [{ "title": searchDetail.title }] } ); } }); // Promise.all(detailsArr).then((data) => { // console.log(data); // console.log(detailsArr); // return data; // }); return Promise.all(detailsArr); }; /* * Get the partially saved details of a case from the appeal type * @param object searchResultsObj */ export const getPartSavedDetails = (searchResultsObj) => { let detailsArr = []; searchResultsObj = searchResultsObj.value; const detailsObj = searchResultsObj.map((searchDetail, index) => { if (searchDetail.pinswg_appealcasetype == null) { console.log(searchDetail.title); } else { let formMeta = getFormCollectionByID( searchDetail.pinswg_appealcasetype ); // console.log(formMeta); detailsArr.push( getBasicPartSavedDetails( formMeta.LogicalCollectionName, searchDetail.title, formMeta.PrimaryIdAttribute, searchDetail.incidentid ) ); } }); return Promise.all(detailsArr); }; /* * Get the details of a case from the appeal type * @param object searchResultsObj */ // export const getSearchDetailsPaged = (searchResultsObj) => { // let detailsArr = []; // searchResultsObj = searchResultsObj.value; // const detailsObj = searchResultsObj.map((searchDetail, index) => { // if (searchDetail.pinswg_appealcasetype == null) { // console.log(searchDetail.title); // } else { // let formMeta = getFormCollectionByID( // searchDetail.pinswg_appealcasetype // ); // formMeta?.LogicalCollectionName && // formMeta?.LogicalCollectionName != "pinswg_sipses" && // detailsArr.push( // getBasicSearchDetailsPaged( // formMeta.LogicalCollectionName, // searchDetail.title, // formMeta.PrimaryIdAttribute, // searchDetail.incidentid // ) // ); // } // }); // return Promise.all(detailsArr); // }; // export const getSearchDetailsPaged = async (searchResultsObj) => { // const searchResults = searchResultsObj.value; // //Group incidents by appeal type // const groupedByAppealType = {}; // searchResults.forEach((incident) => { // const appealType = incident.pinswg_appealcasetype; // if (!appealType) return; // const formMeta = getFormCollectionByID(appealType); // if ( // !formMeta?.LogicalCollectionName || // formMeta.LogicalCollectionName === "pinswg_sipses" // ) // return; // const key = formMeta.LogicalCollectionName; // if (!groupedByAppealType[key]) groupedByAppealType[key] = []; // groupedByAppealType[key].push({ // incidentID: incident.incidentid, // caseReference: incident.title, // primaryIdAttribute: formMeta.PrimaryIdAttribute, // }); // }); // // Make all API calls in parallel per appeal type // const allDetails = await Promise.all( // Object.entries(groupedByAppealType).map( // async ([appealTypeName, incidents]) => { // console.log( // `Fetching details for appeal type: ${appealTypeName}, incidents: ${incidents.length}` // ); // // Fully parallel for each incident // const results = await Promise.all( // incidents.map((i) => // getBasicSearchDetailsPaged( // appealTypeName, // i.caseReference, // i.primaryIdAttribute, // i.incidentID // ).catch((err) => { // console.error( // `Error fetching incident ${i.caseReference}:`, // err // ); // return null; // continue other calls even if one fails // }) // ) // ); // return results.filter((r) => r); // remove nulls from failed calls // } // ) // ); // //Flatten all results into a single array // return allDetails.flat(); // }; export const getSearchDetailsPaged = async (searchResultsObj) => { searchResultsObj = searchResultsObj.value; // Group incidents by appeal type const groupedByAppealType = searchResultsObj.reduce((acc, detail) => { const appealType = detail.pinswg_appealcasetype; if (!appealType) { console.log("No appeal type for:", detail.title); return acc; } if (!acc[appealType]) acc[appealType] = []; acc[appealType].push({ incidentID: detail.incidentid, title: detail.title }); return acc; }, {}); const allDetails = []; // For each appeal type, call getBasicSearchDetailsPaged once with all incident IDs for (const [appealType, incidents] of Object.entries(groupedByAppealType)) { const incidentIDs = incidents.map((i) => i.incidentID); // Get the form meta for this appeal type to access primaryIdAttribute const formMeta = getFormCollectionByID(appealType); if (!formMeta || !formMeta.PrimaryIdAttribute) { console.log(`Missing form metadata for appeal type: ${appealType}`); continue; } // console.log( // `Fetching ${incidentIDs.length} incidents for appeal type: ${appealType} with primaryIdAttribute: ${formMeta.PrimaryIdAttribute}` // ); try { const details = await getBasicSearchDetailsPaged( formMeta.LogicalCollectionName, // appealTypeName null, // caseReference is no longer used in batch formMeta.PrimaryIdAttribute, // primaryIdAttribute incidentIDs // pass array of incidentIDs ); allDetails.push(...details); } catch (err) { consoleLogger(err); } } return allDetails; }; export const getProgressObj = ( formObjXML, titleList, mandatoryFieldsData, props ) => { const parser = new DOMParser(); const BuildFormObj = (formObjXML) => { var doc = parser.parseFromString(formObjXML, "text/xml"); var tabs = xpath.select("//form/tabs/tab[*]", doc); const formObj = Object.keys(tabs).map((key, index) => { var sectionXML = xpath.select( "//tabs/tab[" + (index + 1) + "]//rows/row/control[not(@parentField)]/..", doc ); return BuildRowObj(sectionXML, titleList[key].value); }); const progressObj = Object.keys(formObj).map((key, index) => { let fieldObj = formObj[key].fieldsrowObj; let rowCount = 0; !props.dirty && typeof props.initialValues != "undefined" && Object.keys(fieldObj).map((key, index) => { fieldObj[key].datafieldname in props.initialValues && props.initialValues[fieldObj[key].datafieldname] != null && rowCount++; }); props.dirty && Object.keys(fieldObj).map((key, index) => { fieldObj[key].datafieldname in props.props.form["appealForm"].values && props.props.form["appealForm"].values[ fieldObj[key].datafieldname ] != null && rowCount++; }); return { "title": titleList[key].value, rowCount, "totalFields": formObj[key].fieldsTotal, "allFieldsComplete": titleList[key].value == "Upload documents" ? (_.has(props.props.appealType.fileList, "value") && props.props.appealType.fileList.value.length > 0) || (_.has(props.props.form.appealForm, "values") && Object.keys( props.props.form.appealForm.values ).filter((k) => k.startsWith("pinswg_fileUpload")) .length > 0) : rowCount == formObj[key].fieldsTotal }; }); return progressObj; }; const BuildRowObj = (rowXML, titleList) => { let rowObj = Object.keys(rowXML).map((key, index) => { var doc = parser.parseFromString(rowXML[key].outerHTML, "text/xml"); if (_.isEmpty(rowXML[key].innerHTML)) { (""); } else { var rows = xpath.select("//label/@description", doc); var fieldtype = xpath.select("//@classid", doc); var validation = xpath.select("//@validation", doc); var datafieldname = xpath.select("//@datafieldname", doc); var datafieldcontent = xpath.select("//@datafieldcontent", doc); var parentField = xpath.select("//@parentField", doc); var parentFieldShowOnValue = xpath.select( "//@parentFieldShowOnValue", doc ); var requiredDocumentValue = xpath.select( "//@requiredDocumentValue", doc ); var requiredDocumentLabel = xpath.select( "//@requiredDocumentLabel", doc ); var hint = xpath.select("//label/@hint", doc); var dateStart = xpath.select("//@dateStart", doc); var dateEnd = xpath.select("//@dateEnd", doc); hint = !_.isEmpty(hint) && hint[0].value; validation = !_.isEmpty(validation) ? validation[0].value : []; parentField = !_.isEmpty(parentField) && parentField[0].value; parentFieldShowOnValue = !_.isEmpty(parentFieldShowOnValue) && parentFieldShowOnValue[0].value; datafieldcontent = !_.isEmpty(datafieldcontent) && datafieldcontent[0].value; requiredDocumentValue = !_.isEmpty(requiredDocumentValue) && requiredDocumentValue[0].value; requiredDocumentLabel = !_.isEmpty(requiredDocumentLabel) && requiredDocumentLabel[0].value; dateStart = !_.isEmpty(dateStart) && dateStart[0].value; dateEnd = !_.isEmpty(dateEnd) && dateEnd[0].value; const isRequiredField = jsonpath({ path: "$..value[?(@ && @.LogicalName=='" + datafieldname[0].value + "')]", json: mandatoryFieldsData, eval: true }); if (datafieldname[0].value.includes("pinswg_fileUpload")) { if (typeof isRequiredField[0] != "undefined") { if (isRequiredField[0].RequiredLevel.Value != "None") { //console.log(datafieldname[0].value, validation); return { "fieldType": fieldtype[0].value, "label": rows[0].value, "datafieldname": datafieldname[0].value, "datafieldcontent": datafieldcontent, "validation": validation }; } } else { return { "fieldType": fieldtype[0].value, "label": rows[0].value, "datafieldname": datafieldname[0].value, "key": key, "picklistData": props.props.formData.pickListData, "mandatoryFieldsData": mandatoryFieldsData }; } } else { if (typeof isRequiredField[0] != "undefined") { if (isRequiredField[0].RequiredLevel.Value != "None") { //console.log(datafieldname[0].value, validation); return { "fieldType": fieldtype[0].value, "label": rows[0].value, "datafieldname": datafieldname[0].value, "datafieldcontent": datafieldcontent, "validation": validation }; } else { return null; } } else { return null; } } } }); rowObj = rowObj.filter(function (el) { return el != null; }); rowObj = rowObj.filter(function (el) { return typeof el.validation != "undefined"; }); rowObj = rowObj.filter(function (el) { return el.validation.indexOf("required") > -1; }); const filterUnwanted = (rowObj) => { const required = rowObj.filter((el) => { return !_.isEmpty(el.validation); }); return required; }; return { "title": titleList, "validationFieldsTotal": filterUnwanted(rowObj).length, "fieldsTotal": rowObj.length, "fieldsrowObj": rowObj }; }; const progObj = BuildFormObj(formObjXML); //console.log(progObj); return progObj; }; export const getTempCaseRef = () => { function randomString(length) { return Math.random().toString(36).substr(2, length); } const randomGUID = uuidv4(); return "TMP-" + randomString(5).toUpperCase(); }; export const getThumbnailIconByExtension = (blobName) => { let fileType = blobName.slice(blobName.lastIndexOf(".") + 1); switch (fileType) { case "html": return "/assets/images/documenttypes/html.png"; break; case "txt": return "/assets/images/documenttypes/txt.png"; break; case "doc": return "/assets/images/documenttypes/doc.png"; break; case "pdf": return "/assets/images/documenttypes/pdf.png"; break; case "docx": return "/assets/images/documenttypes/docx.png"; break; case "csv": return "/assets/images/documenttypes/csv.png"; break; case "xlsx": return "/assets/images/documenttypes/xlsx.png"; break; case "zip": return "/assets/images/documenttypes/zip.png"; break; case "jpeg": case "jpg": return "/assets/images/documenttypes/jpg.png"; case "png": return "/assets/images/documenttypes/png.png"; case "tiff": case "tif": return "/assets/images/documenttypes/tif.png"; break; default: return "/assets/images/documenttypes/default.png"; break; } }; export const bytesToSize = (bytes) => { var sizes = ["Bytes", "KB", "MB", "GB", "TB"]; if (bytes == 0) return "0 Byte"; var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); return Math.round(bytes / Math.pow(1024, i), 2) + " " + sizes[i]; }; export const formatDates = (dateObj, showTime) => { var dateObj = new Date(dateObj); var dd = String(dateObj.getDate()).padStart(2, "0"); var mm = String(dateObj.getMonth() + 1).padStart(2, "0"); //January is 0! var yyyy = dateObj.getFullYear(); var hh = dateObj.getHours(); hh = ("0" + hh).slice(-2); var mins = dateObj.getMinutes(); mins = ("0" + mins).slice(-2); const dateStr = showTime ? hh == 0 && mins == 0 ? "" : hh + ":" + mins : dd + "/" + mm + "/" + yyyy + " "; return dateStr; }; export const getDetailsProxy = (resultsObj, detailsType) => { let detailsArr = []; resultsObj = resultsObj.value; const detailsObj = resultsObj.map((searchDetail, index) => { if (searchDetail.pinswg_appealcasetype == null) { console.log( detailsType != "myWatchedCases" ? searchDetail.ticketnumber : searchDetail[ "_pinswg_watchedcase_value@OData.Community.Display.V1.FormattedValue" ] ); } else { detailsArr.push( getPortalModuleDetailsProxy( getFormCollectionByID(searchDetail.pinswg_appealcasetype) .LogicalCollectionName, detailsType != "myWatchedCases" ? searchDetail.ticketnumber : searchDetail[ "_pinswg_watchedcase_value@OData.Community.Display.V1.FormattedValue" ] ) ); } }); return Promise.all(detailsArr); }; export const getDocumentTypeFromFilename = (filename) => { var doctypeCode = "000000"; if (typeof filename != "undefined") { if (filename.indexOf("_-_Statement_of_Case") > 0) doctypeCode = "000000"; else if (filename.indexOf("_-_Application_Form") > 0) doctypeCode = "000001"; else if (filename.indexOf("_-_Site_Ownership_Certificate") > 0) doctypeCode = "000002"; else if (filename.indexOf("_-_Decision_Notice") > 0) doctypeCode = "000003"; else if (filename.indexOf("_-_Site_Location_Plan") > 0) doctypeCode = "000004"; else if (filename.indexOf("_-_Plans_Drawing_Documents") > 0) doctypeCode = "000005"; else if (filename.indexOf("_-_Additional_Plans_Drawings_Documents") > 0) doctypeCode = "000006"; else if (filename.indexOf("_-_Design_and_Access_Statement") > 0) doctypeCode = "000007"; else if (filename.indexOf("_-_NSB_LPA_Additional_Documents") > 0) doctypeCode = "000008"; else if (filename.indexOf("_-_LPA_Correspondence") > 0) doctypeCode = "000009"; else if (filename.indexOf("_-_LPA_Original_Permission") > 0) doctypeCode = "000010"; else if (filename.indexOf("_-_LPA's_Registration_Letter") > 0) doctypeCode = "000011"; else if (filename.indexOf("_-_Environmental_Statement") > 0) doctypeCode = "000012"; else if (filename.indexOf("_-_Cost_of_Application") > 0) doctypeCode = "000013"; else if (filename.indexOf("_-_Other_Relevant_Material") > 0) doctypeCode = "000014"; else if ( filename.indexOf("_-_S106_Agreement_or_Unilateral_Undertaking") > 0 ) doctypeCode = "000015"; } return doctypeCode; }; export const updateLinks = (input) => { const EMPTY_QUILL_PARAGRAPHS_REGEX = /
]*>\s*(?:
| |\s)*\s*<\/p>/gi;
const URL_REGEX = /\b(https?:\/\/[^\s<]+)/gi;
const stripTrailingUrlPunctuation = (url) => {
let cleanUrl = url;
let trailing = "";
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;
}
}
}
}
return { cleanUrl, trailing };
};
const processHtmlString = (htmlString) => {
if (typeof htmlString !== "string" || !htmlString) return htmlString;
let html = htmlString.replace(EMPTY_QUILL_PARAGRAPHS_REGEX, "");
const anchorPlaceholders = [];
html = html.replace(/]*>[\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 `${cleanUrl}${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 updated;
};
export const whichRepType = (props, locale) => {
let repType;
let whichBaseType =
props.currentView?.caseReference.repDetails.representationType ||
formObj.representationForm.values.representationType;
switch (whichBaseType) {
case "Statement":
repType = locale == "cy" ? "Datganiad" : "Statment";
break;
case "Questionnaire":
repType = locale == "cy" ? "Holiadur" : "Questionnaire";
break;
case "Final comments":
repType = locale == "cy" ? "Sylwadau terfynol" : "Final comments";
break;
default:
// code block
}
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;
};