Merged PR 2210: Rep raising and pdf for welsh

Related work items: #22095, #22305
This commit is contained in:
Robert Bond
2026-03-30 11:46:22 +00:00
8 changed files with 285 additions and 86 deletions
+14 -5
View File
@@ -213,7 +213,7 @@ let MakeRepresentation = (props) => {
};
default:
return {
path: `$..[?(@ && @.reference=="${caseReference}")]`,
path: `$..[?(@ && @.ticketnumber=="${ticketnumber}")]`,
json: setCaseQueryObj
};
}
@@ -437,9 +437,14 @@ let MakeRepresentation = (props) => {
const isSpecialistNonHearing = specialistProcess !== 846040001;
const isAppellant =
const involvementType =
props.props?.accountDetails?.accountDetails
?.pinswg_typeofinvolvement === 846040001;
?.pinswg_typeofinvolvement;
const isAppellant = involvementType === 846040001;
const isAgent = involvementType === 846040000;
const isIP = involvementType === 846040061;
//const isLPA = involvementType === 846040000;
const startDate = new Date(
isDNS
@@ -520,11 +525,15 @@ let MakeRepresentation = (props) => {
addRep("Statement");
}
const canSubmitFinalComments = isAppellant || isAgent || isIP || isLPA;
const canAddFinalComments =
isAppellant &&
canSubmitFinalComments &&
isWithin(statementDueDate, finalCommentsDate) &&
(appealType !== 846040004 || isSpecialistNonHearing);
// IP and Agents and LPA can do final comments.
if (canAddFinalComments) {
addRep("Final comments");
}
@@ -962,7 +971,7 @@ let MakeRepresentation = (props) => {
// Find correct case details
let detailsObj = jsonpath({
path: `$..[?(@ && @.pinswg_name=="${caseReference}")]`,
path: `$..[?(@ && @.ticketnumber=="${ticketnumber}")]`,
json: setCaseDetailsObj,
eval: true
})[0];
+9 -7
View File
@@ -158,6 +158,7 @@ let BuildCheckSection = (props) => {
);
pdfObj.filesList = uniqueArray;
pdfObj.locale = locale;
confirmSections
? (setFinaliseAppealProcess(true),
@@ -186,6 +187,9 @@ let BuildCheckSection = (props) => {
};
const triggerAppealDownload = async () => {
if (!downloadAppealForm) {
return;
}
if (downloadInProgress) {
return;
}
@@ -199,8 +203,7 @@ let BuildCheckSection = (props) => {
);
pdfObj.filesList = uniqueArray;
console.log(pdfObj);
pdfObj.locale = locale;
const containerID =
props.accountDetails?.containerID ||
@@ -442,10 +445,9 @@ let BuildCheckSection = (props) => {
</>
) : (
<>
<a
disabled={
confirmSections ? false : true
}
<button
type="button"
disabled={!confirmSections}
className="govuk-button"
data-module="govuk-button"
onClick={async () => {
@@ -454,7 +456,7 @@ let BuildCheckSection = (props) => {
}}
>
{t("newappeal:submit-appeal-button")}
</a>
</button>
<a
className="govuk-link"
href="#"
+59 -17
View File
@@ -4,7 +4,8 @@ import xpath from "xpath";
import {
bytesToSize,
getPickListLabel,
getDocumentTypeFromFilename
getDocumentTypeFromFilename,
getFormCollectionByID
} from "../../components/utils";
import fieldLookup from "../../data/crmfieldlookuptranslations.json";
@@ -15,6 +16,7 @@ import { DOMParser, XMLSerializer } from "@xmldom/xmldom";
export const AppealRow_pdf = (props) => {
let { t } = useTranslation();
let locale = props.props.locale;
const {
formXML,
@@ -146,18 +148,32 @@ export const AppealRow_pdf = (props) => {
return dateString;
}
const FieldsTranslations = (label) => {
const { appealtypes } = router.query;
const FieldsTranslations = (label, locale) => {
const appealtypes = getFormCollectionByID(
props.props.caseObj.pinswg_appealcasetype
).UrlName;
let formObj = jsonpath({
path: "$['" + appealtypes + "']",
const formObj = jsonpath({
path: `$['${appealtypes}'].[?(@.value=="${label}")]`,
json: fieldLookup,
eval: true
});
let labelTrans = label;
return labelTrans;
const item = formObj?.[0];
if (locale === "cy" && !item?.value_cy) {
console.warn(`[Missing Welsh translation]`, {
label: item?.value,
orig: label,
appealType: appealtypes
});
}
return locale === "cy"
? (item?.value_cy ?? item?.value ?? label)
: (item?.value ?? label);
};
Font.registerHyphenationCallback((word) => [word]);
function CleanHTML(htmlStr) {
@@ -219,8 +235,10 @@ export const AppealRow_pdf = (props) => {
<Text
style={styles.questionTextWide}
>
{/* {FieldsTranslations(rows[0].value)} */}
{rows[0].value}
{FieldsTranslations(
rows[0].value,
locale
)}{" "}
</Text>
<Text
@@ -260,7 +278,10 @@ export const AppealRow_pdf = (props) => {
styles.questionTextMid
}
>
{rows[0].value}
{FieldsTranslations(
rows[0].value,
locale
)}
</Text>
</View>
<View
@@ -335,7 +356,10 @@ export const AppealRow_pdf = (props) => {
styles.questionTextWide
}
>
{rows[0].value}{" "}
{FieldsTranslations(
rows[0].value,
locale
)}{" "}
</Text>
</View>
<View
@@ -368,7 +392,10 @@ export const AppealRow_pdf = (props) => {
styles.questionTextWide
}
>
{rows[0].value}
{FieldsTranslations(
rows[0].value,
locale
)}
</Text>
</View>
<View
@@ -399,7 +426,10 @@ export const AppealRow_pdf = (props) => {
>
<Text style={styles.questionText}>
{/* {FieldsTranslations(rows[0].value)} */}
{rows[0].value}
{FieldsTranslations(
rows[0].value,
locale
)}
</Text>
<Text style={styles.questionAnswer}>
{getPickListLabel(
@@ -453,7 +483,10 @@ export const AppealRow_pdf = (props) => {
styles.questionTextWide
}
>
{rows[0].value}
{FieldsTranslations(
rows[0].value,
locale
)}
</Text>
</View>
@@ -524,7 +557,10 @@ export const AppealRow_pdf = (props) => {
styles.questionTextMid
}
>
{rows[0].value}
{FieldsTranslations(
rows[0].value,
locale
)}
</Text>
</View>
<View
@@ -638,7 +674,10 @@ export const AppealRow_pdf = (props) => {
style={styles.questionText}
wrap={false}
>
{rows[0].value}
{FieldsTranslations(
rows[0].value,
locale
)}
</Text>
<Text
style={
@@ -665,7 +704,10 @@ export const AppealRow_pdf = (props) => {
}}
>
<Text style={styles.questionText}>
{rows[0].value}
{FieldsTranslations(
rows[0].value,
locale
)}
</Text>
<Text style={styles.questionAnswer}>
{
+142 -53
View File
@@ -6,7 +6,7 @@ import ReactPDF, {
Image,
StyleSheet,
PDFViewer,
Font,
Font
} from "@react-pdf/renderer";
import Html from "react-pdf-html";
import { getFormCollectionByID, bytesToSize } from "../utils";
@@ -17,28 +17,42 @@ import _ from "lodash";
import { DOMParser, XMLSerializer } from "@xmldom/xmldom";
import { AppealRow_pdf } from "./appealRow_pdf";
import transLookupCY from "../../locales/cy/newappeal.json";
import transLookupEN from "../../locales/en/newappeal.json";
import fieldLookup from "../../data/crmfieldlookuptranslations.json";
import { JSONPath as jsonpath } from "jsonpath-plus";
const getTrans = (locale, key) => {
let jsonQuery = `$.${key}`;
let jsonObj = locale == "cy" ? transLookupCY : transLookupEN;
//console.log(locale, jsonObj[key]);
return jsonObj[key];
};
const styles = StyleSheet.create({
page: {
backgroundColor: "white",
padding: 20,
fontSize: 16,
paddingBottom: 50,
paddingBottom: 50
},
header: {
fontSize: 25,
fontFamily: "Helvetica",
flexDirection: "row",
justifyContent: "space-between",
justifyContent: "space-between"
},
subHeader: {
fontSize: 20,
fontSize: 20
},
logoImage: { width: "200pt" },
questionBullet: { width: "5%", fontSize: 12 },
questionText: {
width: "35%",
fontSize: 12,
fontFamily: "Helvetica-Bold",
fontFamily: "Helvetica-Bold"
},
questionTextMid: { width: "80%", fontSize: 12 },
questionTextWide: { width: "95%", fontSize: 12, marginBottom: 5 },
@@ -50,7 +64,7 @@ const styles = StyleSheet.create({
border: 1,
borderColor: "#eee",
paddingLeft: 10,
backgroundColor: "white",
backgroundColor: "white"
},
questionAnswerMid: {
color: "#757575",
@@ -60,7 +74,7 @@ const styles = StyleSheet.create({
border: 1,
borderColor: "#eee",
paddingLeft: 10,
backgroundColor: "white",
backgroundColor: "white"
},
questionAnswerWide: {
color: "#757575",
@@ -70,14 +84,14 @@ const styles = StyleSheet.create({
border: 1,
borderColor: "#eee",
backgroundColor: "white",
padding: 5,
padding: 5
},
sectionContainer: {
backgroundColor: "#F8F8F8",
padding: 10,
marginTop: 20,
fontSize: 15,
fontSize: 15
},
pageNumber: {
position: "absolute",
@@ -86,17 +100,18 @@ const styles = StyleSheet.create({
left: 0,
right: 0,
textAlign: "center",
color: "grey",
color: "grey"
},
richArea: {
fontSize: 12,
flexDirection: "column",
},
flexDirection: "column"
}
});
export const planningappeals78_pdf = ({ docProps, pickListData }) => {
//console.log("----", docProps);
const locale = docProps.locale;
function formatDates(dateObj) {
var dateObj = new Date(dateObj);
var dd = String(dateObj.getDate()).padStart(2, "0");
@@ -145,6 +160,32 @@ export const planningappeals78_pdf = ({ docProps, pickListData }) => {
Font.registerHyphenationCallback((word) => [word]);
const FieldsTranslations = (label, locale) => {
const appealtypes = getFormCollectionByID(
docProps.caseObj.pinswg_appealcasetype
).UrlName;
const formObj = jsonpath({
path: `$['${appealtypes}'].[?(@.value=="${label}")]`,
json: fieldLookup,
eval: true
});
const item = formObj?.[0];
if (locale === "cy" && !item?.value_cy) {
console.warn(`[Missing Welsh translation]`, {
label: item?.value,
orig: label,
appealType: appealtypes
});
}
return locale === "cy"
? (item?.value_cy ?? item?.value ?? label)
: (item?.value ?? label);
};
return (
<Document>
<Page size="A4" style={styles.page} wrap>
@@ -154,10 +195,10 @@ export const planningappeals78_pdf = ({ docProps, pickListData }) => {
<Text
style={{
width: "60%",
fontFamily: "Helvetica-Bold",
fontFamily: "Helvetica-Bold"
}}
>
Planning Appeals s78
{getTrans(locale, "pdf-s78-heading")}
</Text>
<View>
<Text
@@ -165,12 +206,14 @@ export const planningappeals78_pdf = ({ docProps, pickListData }) => {
width: "60%",
fontSize: 15,
marginTop: 20,
fontFamily: "Helvetica-Bold",
fontFamily: "Helvetica-Bold"
}}
>
For Planning, Conservation area, Listed
Building and Advertisement
applications/appeals
{" "}
{getTrans(
locale,
"pdf-s78-header-paragraph"
)}
</Text>
</View>
</View>
@@ -188,23 +231,27 @@ export const planningappeals78_pdf = ({ docProps, pickListData }) => {
<View
style={{
marginTop: 10,
fontFamily: "Helvetica-Bold",
fontFamily: "Helvetica-Bold"
}}
>
<Text style={{ fontSize: 14 }}>
{parseInt(key)} {titles[key].value}
{parseInt(key)}{" "}
{FieldsTranslations(
titles[key].value,
locale
)}
</Text>
<View style={styles.sectionContainer}>
<View
style={{
flexDirection: "row",
marginBottom: 10,
marginBottom: 10
}}
>
<View
style={{
flexDirection: "column",
marginBottom: 10,
marginBottom: 10
}}
>
<AppealRow_pdf
@@ -252,7 +299,7 @@ export const planningappeals78_pdf = ({ docProps, pickListData }) => {
borderColor: "#eee",
padding: 20,
paddingTop: 30,
height: "100%",
height: "100%"
}}
></View>
</Page>
@@ -261,33 +308,39 @@ export const planningappeals78_pdf = ({ docProps, pickListData }) => {
<View
style={{
marginTop: 10,
fontFamily: "Helvetica-Bold",
fontFamily: "Helvetica-Bold"
}}
>
<Text style={{ fontSize: 14 }}>Case Details</Text>
<Text style={{ fontSize: 14 }}>
{" "}
{getTrans(locale, "pdf-s78-heading")}
</Text>
<View style={styles.sectionContainer}>
<View
wrap={false}
style={{
flexDirection: "row",
marginBottom: 10,
marginBottom: 10
}}
>
<View
style={{
flexDirection: "column",
marginBottom: 10,
marginBottom: 10
}}
>
<View
wrap={false}
style={{
flexDirection: "row",
marginBottom: 10,
marginBottom: 10
}}
>
<Text style={styles.questionText}>
Appeal submitted on behalf of:
{getTrans(
locale,
"pdf-case-details-label-1"
)}
</Text>
<Text style={styles.questionAnswer}>
{" "}
@@ -298,11 +351,14 @@ export const planningappeals78_pdf = ({ docProps, pickListData }) => {
wrap={false}
style={{
flexDirection: "row",
marginBottom: 10,
marginBottom: 10
}}
>
<Text style={styles.questionText}>
Appellant or Agent
{getTrans(
locale,
"pdf-case-details-label-2"
)}
</Text>
<Text style={styles.questionAnswer}>
{" "}
@@ -317,11 +373,14 @@ export const planningappeals78_pdf = ({ docProps, pickListData }) => {
wrap={false}
style={{
flexDirection: "row",
marginBottom: 10,
marginBottom: 10
}}
>
<Text style={styles.questionText}>
Appellant name
{getTrans(
locale,
"pdf-case-details-label-3"
)}
</Text>
<Text style={styles.questionAnswer}>
{values.caseObj
@@ -335,11 +394,14 @@ export const planningappeals78_pdf = ({ docProps, pickListData }) => {
wrap={false}
style={{
flexDirection: "row",
marginBottom: 10,
marginBottom: 10
}}
>
<Text style={styles.questionText}>
Appellant email address
{getTrans(
locale,
"pdf-case-details-label-4"
)}
</Text>
<Text style={styles.questionAnswer}>
{
@@ -352,11 +414,14 @@ export const planningappeals78_pdf = ({ docProps, pickListData }) => {
wrap={false}
style={{
flexDirection: "row",
marginBottom: 10,
marginBottom: 10
}}
>
<Text style={styles.questionText}>
Appellant address
{getTrans(
locale,
"pdf-case-details-label-5"
)}
</Text>
<Text style={styles.questionAnswer}>
{
@@ -369,11 +434,14 @@ export const planningappeals78_pdf = ({ docProps, pickListData }) => {
wrap={false}
style={{
flexDirection: "row",
marginBottom: 10,
marginBottom: 10
}}
>
<Text style={styles.questionText}>
Appellant phone number
{getTrans(
locale,
"pdf-case-details-label-3"
)}
</Text>
<Text style={styles.questionAnswer}>
{" "}
@@ -390,13 +458,16 @@ export const planningappeals78_pdf = ({ docProps, pickListData }) => {
wrap={false}
style={{
flexDirection: "row",
marginBottom: 10,
marginBottom: 10
}}
>
<Text
style={styles.questionText}
>
Company name
{getTrans(
locale,
"pdf-case-details-agent-label-1"
)}
</Text>
<Text
style={
@@ -413,13 +484,16 @@ export const planningappeals78_pdf = ({ docProps, pickListData }) => {
wrap={false}
style={{
flexDirection: "row",
marginBottom: 10,
marginBottom: 10
}}
>
<Text
style={styles.questionText}
>
Agent name
{getTrans(
locale,
"pdf-case-details-agent-label-2"
)}
</Text>
<Text
style={
@@ -440,13 +514,16 @@ export const planningappeals78_pdf = ({ docProps, pickListData }) => {
wrap={false}
style={{
flexDirection: "row",
marginBottom: 10,
marginBottom: 10
}}
>
<Text
style={styles.questionText}
>
Agent email address
{getTrans(
locale,
"pdf-case-details-agent-label-3"
)}
</Text>
<Text
style={
@@ -463,13 +540,16 @@ export const planningappeals78_pdf = ({ docProps, pickListData }) => {
wrap={false}
style={{
flexDirection: "row",
marginBottom: 10,
marginBottom: 10
}}
>
<Text
style={styles.questionText}
>
Agent address
{getTrans(
locale,
"pdf-case-details-agent-label-4"
)}
</Text>
<Text
style={
@@ -486,13 +566,16 @@ export const planningappeals78_pdf = ({ docProps, pickListData }) => {
wrap={false}
style={{
flexDirection: "row",
marginBottom: 10,
marginBottom: 10
}}
>
<Text
style={styles.questionText}
>
Agent phone number
{getTrans(
locale,
"pdf-case-details-agent-label-5"
)}
</Text>
<Text
style={
@@ -512,11 +595,14 @@ export const planningappeals78_pdf = ({ docProps, pickListData }) => {
wrap={false}
style={{
flexDirection: "row",
marginBottom: 10,
marginBottom: 10
}}
>
<Text style={styles.questionText}>
LPA
{getTrans(
locale,
"pdf-case-details-label-7"
)}
</Text>
<Text style={styles.questionAnswer}>
{values.caseObj.pinswg_lpaname ||
@@ -547,11 +633,14 @@ export const planningappeals78_pdf = ({ docProps, pickListData }) => {
wrap={false}
style={{
flexDirection: "row",
marginBottom: 10,
marginBottom: 10
}}
>
<Text style={styles.questionText}>
Language Preference
{getTrans(
locale,
"pdf-case-details-label-8"
)}
</Text>
<Text style={styles.questionAnswer}>
{values.caseObj
+13 -1
View File
@@ -2231,7 +2231,7 @@
"value_cy": "A yw'n hanfodol i'r Arolygydd fynd i mewn i'r safle i wirio mesuriadau neu ffeithiau eraill perthnasol?"
},
{
"value": "Please explain why the inspector needs to enter the site",
"value": "Please explain why the Inspector needs to enter the site",
"value_cy": "Eglurwch pam mae angen i'r Arolygydd fynd i mewn i'r safle"
},
{
@@ -2433,6 +2433,18 @@
{
"value": "The S106 agreement or unilateral undertaking",
"value_cy": "Cytundeb S106 neu ymgymeriad unochrog"
},
{
"value": "Owner",
"value_cy": "Perchennog"
},
{
"value": "Tenant name",
"value_cy": "Enw tenant"
},
{
"value": "Please submit your statement of case",
"value_cy": "Cyflwynwch eich datganiad achos"
}
]
}
+23 -1
View File
@@ -123,5 +123,27 @@
"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",
"return-to-myportal-link": "Dychwelyd i Fy Mhorth"
"return-to-myportal-link": "Dychwelyd i Fy Mhorth",
"pdf-s78-heading": "Apelau Cynllunio s78",
"pdf-s78-header-paragraph": "Ar gyfer ceisiadau/apelau Cynllunio, Ardal Gadwraeth, Adeilad Rhestredig a Hysbysebu",
"pdf-heading-1": "Manylion yr apêl",
"pdf-case-subheading-1": "Manylion perchnogaeth safle'r apêl",
"pdf-case-subheading-2": "Gwybodaeth am ymweliad â'r safle",
"pdf-case-subheading-3": "Apelau eraill",
"pdf-case-subheading-4": "Cyflwyno achos",
"pdf-case-subheading-5": "Uwchlwytho dogfennau",
"pdf-case-details-subheading": "Manylion yr Achos",
"pdf-case-details-label-1": "Apel a gyflwynwyd ar ran",
"pdf-case-details-label-2": "Apelydd neu Asiant",
"pdf-case-details-label-3": "Enw'r apelydd",
"pdf-case-details-label-4": "E-bost yr apelydd",
"pdf-case-details-label-5": "Cyfeiriad yr apelydd",
"pdf-case-details-label-6": "Rhif ffôn yr apelydd",
"pdf-case-details-label-7": "LPA",
"pdf-case-details-label-8": "Dewis Iaith",
"pdf-case-details-agent-label-1": "Enw'r cwmni",
"pdf-case-details-agent-label-2": "Enw'r asiant",
"pdf-case-details-agent-label-3": "Cyfeiriad e-bost yr asiant",
"pdf-case-details-agent-label-4": "Cyfeiriad yr asiant",
"pdf-case-details-agent-label-5": "Rhif ffôn yr asiant"
}
+23 -1
View File
@@ -123,5 +123,27 @@
"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",
"return-to-myportal-link": "Return to My Portal"
"return-to-myportal-link": "Return to My Portal",
"pdf-s78-heading": "Planning Appeals s78",
"pdf-s78-header-paragraph": "For Planning, Conservation area, Listed Building and Advertisement applications/appeals",
"pdf-heading-1": "Appeal details",
"pdf-case-subheading-1": "Appeal site ownership details",
"pdf-case-subheading-2": "Site visit information",
"pdf-case-subheading-3": "Other appeals",
"pdf-case-subheading-4": "Submission of case",
"pdf-case-subheading-5": "Upload documents",
"pdf-case-details-subheading": "Case Details",
"pdf-case-details-label-1": "Appeal submitted on behalf of",
"pdf-case-details-label-2": "Appellant or Agent",
"pdf-case-details-label-3": "Appellant name",
"pdf-case-details-label-4": "Appellant email address",
"pdf-case-details-label-5": "Appellant address",
"pdf-case-details-label-6": "Appellant phone number",
"pdf-case-details-label-7": "LPA",
"pdf-case-details-label-8": "Language Preference",
"pdf-case-details-agent-label-1": "Company name",
"pdf-case-details-agent-label-2": "Agent name",
"pdf-case-details-agent-label-3": "Agent email address",
"pdf-case-details-agent-label-4": "Agent address",
"pdf-case-details-agent-label-5": "Agent phone number"
}
+2 -1
View File
@@ -100,6 +100,7 @@ export default async function handler(req, res) {
typeof req.body === "string" ? JSON.parse(req.body) : req.body;
const containerID = appealBodyObj.containerID;
const casefolderID = appealBodyObj.casefolderID;
const locale = appealBodyObj.locale || "en";
let checkquerypath = "/api/file/generateappealpdf";
if (
@@ -207,7 +208,7 @@ export default async function handler(req, res) {
const renderedPDF = await ReactPDF.renderToStream(
MyDocument({
docProps: blobProgress,
docProps: { ...blobProgress, locale },
pickListData: pickListData
})
);