Merged PR 1394: PII-UAT 270125

This commit is contained in:
Robert Bond
2025-01-28 13:53:54 +00:00
5 changed files with 78 additions and 63 deletions
+4 -3
View File
@@ -865,6 +865,7 @@ let MakeRepresentation = (props) => {
? (Object.assign(values, { ? (Object.assign(values, {
"filesList": props.currentView.fileList, "filesList": props.currentView.fileList,
}), }),
(values = updateLinks(values)),
uploadRepresentationFiles(values), uploadRepresentationFiles(values),
router.replace( router.replace(
router.locale != "en" router.locale != "en"
@@ -875,6 +876,7 @@ let MakeRepresentation = (props) => {
"filesList": props.currentView.fileList, "filesList": props.currentView.fileList,
}), }),
console.log("Rep Updated - ", props.caseReference), console.log("Rep Updated - ", props.caseReference),
(values = updateLinks(values)),
uploadRepresentationFiles(values); uploadRepresentationFiles(values);
}; };
@@ -1046,7 +1048,8 @@ let MakeRepresentation = (props) => {
).then((data) => { ).then((data) => {
console.log(data); console.log(data);
data.status == "success" && data.status == "success" &&
(uploadRepresentationFiles(values), ((values = updateLinks(values)),
uploadRepresentationFiles(values),
setRepresentationSubmit(true), setRepresentationSubmit(true),
setRepresentationSubmitConfirmation(true)); setRepresentationSubmitConfirmation(true));
}); });
@@ -1100,8 +1103,6 @@ let MakeRepresentation = (props) => {
? cleanFilesList(values) ? cleanFilesList(values)
: values; : values;
values = updateLinks(values);
// get filelists from values object // get filelists from values object
let fileListObj = _.filter(values, function (v, key) { let fileListObj = _.filter(values, function (v, key) {
return _.includes(key, "representationDocuments"); return _.includes(key, "representationDocuments");
@@ -2,7 +2,7 @@ import useTranslation from "next-translate/useTranslation";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import Link from "next/link"; import Link from "next/link";
import router from "next/router"; import router from "next/router";
import React, { useMemo, useState } from "react"; import React, { useMemo, useState, useRef } from "react";
import DatePicker from "react-datepicker"; import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css"; import "react-datepicker/dist/react-datepicker.css";
import Dropzone from "react-dropzone"; import Dropzone from "react-dropzone";
@@ -726,7 +726,7 @@ export const RenderMultiline = ({
toolbar: [ toolbar: [
[{ "header": [1, 2, false] }], [{ "header": [1, 2, false] }],
["bold", "italic", "underline", "blockquote"], ["bold", "italic", "underline", "blockquote"],
[{ "list": "ordered" }, { "list": "bullet" }, "link"], [{ "list": "ordered" }, { "list": "bullet" }],
["clean"], ["clean"],
], ],
}; };
@@ -889,9 +889,10 @@ let Enforcement_Questionnaire = (props) => {
)} )}
component={RenderLPACondtionalRadioList} component={RenderLPACondtionalRadioList}
validate={[required]} validate={[required]}
legend={t( legend={
"myrepresentations:enf-section-question-31a" "a) " +
)} t("myrepresentations:enf-section-question-31a")
}
conditionalLabel={t( conditionalLabel={t(
"myrepresentations:enf-section-question-31a-hint" "myrepresentations:enf-section-question-31a-hint"
)} )}
@@ -901,7 +902,10 @@ let Enforcement_Questionnaire = (props) => {
/> />
</div> </div>
<Field <Field
label={t("myrepresentations:enf-section-question-31b")} label={
"b) " +
t("myrepresentations:enf-section-question-31b")
}
name="developmentNotTakePlaceBiodiversity" name="developmentNotTakePlaceBiodiversity"
id="developmentNotTakePlaceBiodiversity" id="developmentNotTakePlaceBiodiversity"
component={RenderRadioList} component={RenderRadioList}
@@ -915,7 +919,10 @@ let Enforcement_Questionnaire = (props) => {
aria-describedby={props.name + "-hint"} aria-describedby={props.name + "-hint"}
/> />
<Field <Field
label={t("myrepresentations:enf-section-question-31c")} label={
"c) " +
t("myrepresentations:enf-section-question-31c")
}
name="developmentNotTakePlaceBroadband" name="developmentNotTakePlaceBroadband"
id="developmentNotTakePlaceBroadband" id="developmentNotTakePlaceBroadband"
component={RenderRadioList} component={RenderRadioList}
+59 -53
View File
@@ -551,66 +551,72 @@ export const getDocumentTypeFromFilename = (filename) => {
return doctypeCode; return doctypeCode;
}; };
export const updateLinks = (jsonObject) => { export const updateLinks = (jsonObj) => {
const wrapPlainUrlsInAnchorTags = (htmlString) => { const parser = new DOMParser();
return htmlString
.replace( // Function to process the HTML string and replace URLs with <a> tags
/(?<=^|>|\s)(?=\S)(?:https?:\/\/)?(?:www\.)?[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(?:\/[^\s]*)?(?=\s|<|$)/g, const processHtmlString = (htmlString) => {
(match) => { const doc = parser.parseFromString(htmlString, "text/html");
// If the match is already wrapped in <a> tag, return it as is
if (match.includes('<a href="') || match.includes("<a ")) { // Find all text nodes in the document
return match; const walk = (node) => {
if (node.nodeType === Node.TEXT_NODE) {
// Check if the text node contains a URL (simple check for a URL pattern)
const urlRegex =
/(?:https?:\/\/)?(?:www\.)?([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})(\/[^\s]*)?/g;
let match;
// Process the text node if it contains a URL
while ((match = urlRegex.exec(node.textContent)) !== null) {
// Construct the full URL by adding the protocol if missing, and the domain and path
let fullUrl = match[0];
if (
!fullUrl.startsWith("http://") &&
!fullUrl.startsWith("https://")
) {
fullUrl = `https://${match[1]}${match[2] || ""}`; // Default to https
} }
// Check if the URL starts with http:// or https://, else prepend http://
const url =
match.startsWith("http://") ||
match.startsWith("https://")
? match
: "https://" + match;
// Return the URL wrapped in <a> tag // Check if the match is already inside an <a> tag, if so, skip it
return `<a href="${url}" rel="noopener noreferrer" target="_blank">${match}</a>`; if (node.parentNode.tagName !== "A") {
const anchor = document.createElement("a");
anchor.href = fullUrl;
anchor.textContent = match[0];
// Add rel="noopener noreferrer" for security
anchor.setAttribute("rel", "noopener noreferrer");
// Replace the URL with the anchor element in the text node
const range = document.createRange();
range.selectNodeContents(node);
range.deleteContents();
range.insertNode(anchor);
}
} }
)
.replace(
/<a [^>]*><a [^>]*>(.*?)<\/a><\/a>/g,
(match, innerContent) => {
return `<a href="${innerContent}" rel="noopener noreferrer" target="_blank">${innerContent}</a>`;
}
);
};
// Helper function to ensure that any href attributes in <a> tags have https/http
const ensureHttpsInLinks = (inputString) => {
// Match <a> tags with href attributes and check if they lack a scheme (http:// or https://)
return inputString.replace(
/<a [^>]*href=["']([^"']*)["'][^>]*>/g,
(match, url) => {
// If the URL doesn't already have a scheme (http:// or https://), add https://
if (!/^https?:\/\//.test(url)) {
const newUrl = `https://${url}`;
return match.replace(url, newUrl);
}
return match; // Return the unchanged anchor tag if it already has a scheme
} }
);
// Traverse child nodes
for (let i = 0; i < node.childNodes.length; i++) {
walk(node.childNodes[i]);
}
};
walk(doc.body);
return doc.body.innerHTML;
}; };
// Iterate through all properties of the JSON object // Iterate over the JSON object and process values that are strings (HTML content)
Object.keys(jsonObject).forEach((key) => { for (const key in jsonObj) {
const value = jsonObject[key]; if (jsonObj.hasOwnProperty(key)) {
const value = jsonObj[key];
// If the value is a string and contains plain URLs that are not wrapped // If the value is a string and contains HTML, process it
if (typeof value === "string") { if (typeof value === "string" && /<[^>]*>/g.test(value)) {
// Step 1: Wrap plain URLs in anchor tags if not already wrapped jsonObj[key] = processHtmlString(value);
let updatedValue = wrapPlainUrlsInAnchorTags(value); }
// Step 2: Ensure that hrefs in anchor tags have https:// or http://
updatedValue = ensureHttpsInLinks(updatedValue);
// Assign the updated value back to the key
jsonObject[key] = updatedValue;
} }
}); }
return jsonObject; return jsonObj;
}; };
+1
View File
@@ -76,6 +76,7 @@
"react-leaflet": "^4.2.1", "react-leaflet": "^4.2.1",
"react-pdf": "^7.6.0", "react-pdf": "^7.6.0",
"react-pdf-html": "^1.1.18", "react-pdf-html": "^1.1.18",
"react-quill": "^2.0.0",
"react-quill-new": "^3.3.3", "react-quill-new": "^3.3.3",
"react-redux": "^7.2.6", "react-redux": "^7.2.6",
"redux": "^4.2.1", "redux": "^4.2.1",