rich text field and pdf create for appeal

This commit is contained in:
2024-01-16 14:23:11 +00:00
parent e0badd6b11
commit 5f82c59abb
30 changed files with 592 additions and 288 deletions
+277 -109
View File
@@ -25,6 +25,7 @@ import {
getThumbnailIconByExtension,
bytesToSize,
} from "../utils";
import dynamic from "next/dynamic";
import {
addYears,
@@ -35,6 +36,8 @@ import {
subDays,
parseISO,
} from "date-fns";
const ReactQuill = dynamic(() => import("react-quill"), { ssr: false });
import "react-quill/dist/quill.snow.css";
const RenderTextfield = ({
id,
@@ -66,7 +69,16 @@ const RenderTextfield = ({
{errorMsg}
</span>
)}
<input {...input} className={className} name={name} id={id} />
<input
{...input}
className={className}
name={name}
id={id}
maxLength={
custom.hasOwnProperty("maxFieldLength") &&
custom.maxFieldLength
}
/>
</div>
</>
);
@@ -82,6 +94,7 @@ export function Textfield(props) {
formProps,
parentField,
parentFieldShowOnValue,
maxFieldLength,
hint,
} = props;
const required = (value) => (value ? undefined : "Required");
@@ -134,6 +147,7 @@ export function Textfield(props) {
validate={eval(validation)}
label={props.label}
errorMsg="Is required"
maxFieldLength={props.maxFieldLength}
/>
)
) : (
@@ -146,6 +160,7 @@ export function Textfield(props) {
validate={eval(validation)}
label={props.label}
errorMsg="Is required"
maxFieldLength={props.maxFieldLength}
/>
)}
</div>
@@ -193,6 +208,11 @@ const RenderMultiline = ({
rows={rows}
className={className}
{...input}
maxLength={
custom.hasOwnProperty("maxFieldLength")
? custom.maxFieldLength
: ""
}
></textarea>
</div>
</>
@@ -208,6 +228,7 @@ export function MultiLinefield(props) {
parentField,
parentFieldShowOnValue,
validation,
maxFieldLength,
} = props;
const required = (value) => (value ? undefined : "Is required");
@@ -249,6 +270,7 @@ export function MultiLinefield(props) {
className="govuk-textarea govuk-input--width-30"
aria-describedby={props.name + "-hint"}
validate={eval(validation)}
maxFieldLength={props.maxFieldLength}
/>
</div>
)
@@ -275,6 +297,146 @@ export function MultiLinefield(props) {
className="govuk-textarea govuk-input--width-30"
aria-describedby={props.name + "-hint"}
validate={eval(validation)}
maxFieldLength={props.maxFieldLength}
/>
</div>
)}
</>
);
}
export const RenderRichMultiline = ({
id,
className,
rows,
datafieldname,
name,
label,
input,
meta: { touched, error },
...custom
}) => {
const [editValue, setEditValue] = useState(
input.value != null ? input.value : ""
);
const changeEdit = (valStr) => {
setEditValue(valStr);
input.onChange(valStr);
};
var modules = {
toolbar: [
[{ "header": [1, 2, false] }],
["bold", "italic", "underline", "blockquote"],
[{ "list": "ordered" }, { "list": "bullet" }],
["clean"],
],
};
return (
<>
<label className="govuk-label" htmlFor={name}>
{label}
</label>
<ReactQuill
modules={modules}
theme="snow"
value={editValue}
onChange={changeEdit}
/>
<textarea
{...input}
id={id}
name={name}
rows={rows}
className={className}
value={editValue}
style={{ display: "none" }}
></textarea>
</>
);
};
export function RichMultiLinefield(props) {
const {
name,
label,
form,
formProps,
parentField,
parentFieldShowOnValue,
validation,
maxFieldLength,
} = props;
const required = (value) => (value ? undefined : "Is required");
var showIfHasParentShowValue =
parentField != false &&
!_.isEmpty(formProps[form]) &&
_.has(formProps[form].values, parentField) &&
parentFieldShowOnValue.indexOf(
formProps[form].values[parentField].toString()
) > -1;
(showIfHasParentShowValue == parentField) != false &&
showIfHasParentShowValue;
//console.log(showIfHasParentShowValue, formProps[form].values[parentField]);
return (
<>
{parentField != false ? (
showIfHasParentShowValue && (
<div>
<h1 className="govuk-label-wrapper">
<label className="govuk-label" htmlFor={props.name}>
{FieldsTranslations(props.label)}
</label>
</h1>
<div
id={props.name + "-hint"}
className="govuk-hint govuk-!-font-size-14"
>
Do not include personal or financial information.
</div>
<Field
name={props.name}
id={props.name}
component={RenderRichMultiline}
type="text"
rows="5"
className="govuk-textarea govuk-input--width-30"
aria-describedby={props.name + "-hint"}
validate={eval(validation)}
maxFieldLength={props.maxFieldLength}
/>
</div>
)
) : (
<div className="govuk-form-group">
<h1 className="govuk-label-wrapper">
<label className="govuk-label" htmlFor={props.name}>
{FieldsTranslations(props.label)}
</label>
</h1>
<div
id={props.name + "-hint"}
className="govuk-hint govuk-!-font-size-14"
>
Do not include personal or financial information.
</div>
<Field
name={props.name}
id={props.name}
component={RenderRichMultiline}
type="text"
rows="5"
className="govuk-textarea govuk-input--width-30"
aria-describedby={props.name + "-hint"}
validate={eval(validation)}
maxFieldLength={props.maxFieldLength}
/>
</div>
)}
@@ -1087,6 +1249,7 @@ export function NumericField(props) {
validate={eval(validation)}
component={RenderTextfield}
label={label}
maxFieldLength={props.maxFieldLength}
/>
</div>
)
@@ -1121,6 +1284,7 @@ export function DecimalField(props) {
formProps,
parentFieldShowOnValue,
parentField,
maxFieldLength,
} = props;
const required = (value) => (value ? undefined : "Required");
@@ -1157,6 +1321,7 @@ export function DecimalField(props) {
validate={eval(validation)}
component={RenderTextfield}
label={props.label}
maxFieldLength={props.maxFieldLength}
/>
</div>
)
@@ -1431,121 +1596,124 @@ const RenderFileUpload = (field) => {
});
};
return <>
<Dropzone
accept="application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,image/tiff,image/jpeg,application/zip"
onDrop={(filesToUpload, e) => {
const renamedAcceptedFiles = filesToUpload.map(
(file) =>
new File(
[file],
`${getDocumentType(field.documentTypeCode)}_${
file.name
}`,
{
type: file.type,
}
)
);
field.input.onChange(renamedAcceptedFiles);
}}
>
{({ getRootProps, getInputProps }) => (
<>
{/* {field.hint != false && (
return (
<>
<Dropzone
accept="application/pdf,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,image/tiff,image/jpeg,application/zip"
onDrop={(filesToUpload, e) => {
const renamedAcceptedFiles = filesToUpload.map(
(file) =>
new File(
[file],
`${getDocumentType(field.documentTypeCode)}_${
file.name
}`,
{
type: file.type,
}
)
);
field.input.onChange(renamedAcceptedFiles);
}}
>
{({ getRootProps, getInputProps }) => (
<>
{/* {field.hint != false && (
<div className="govuk-hint">ss{t(field.hint)}</div>
)}
<div className="govuk-form-group"></div> */}
<section className="container">
<div {...getRootProps({ style })}>
{" "}
<input id={field.id} {...getInputProps()} />
<div>
{t(
"newappeal:new-appeal-fileupload-drop-label"
)}
<section className="container">
<div {...getRootProps({ style })}>
{" "}
<input id={field.id} {...getInputProps()} />
<div>
{t(
"newappeal:new-appeal-fileupload-drop-label"
)}
</div>
<em>
(
{t(
"newappeal:new-appeal-fileupload-file-list-label"
)}
)
</em>
</div>
<em>
(
{t(
"newappeal:new-appeal-fileupload-file-list-label"
)}
)
</em>
</div>
<aside>{thumbs}</aside>
</section>
</>
<aside>{thumbs}</aside>
</section>
</>
)}
</Dropzone>
{field.meta.touched && field.meta.error && (
<span className="error">{field.meta.error}</span>
)}
</Dropzone>
{field.meta.touched && field.meta.error && (
<span className="error">{field.meta.error}</span>
)}
{files && Array.isArray(files) && (
<ul>
{files.map((file, i) => (
<div
key={file.name}
className="govuk-!-margin-bottom-5 fileThumb"
>
<img
src={getThumbnailIcon(file, file.type)}
alt={file.name}
width="50"
/>
<span className="govuk-body govuk-!-font-size-14 govuk-!-padding-left-5">
{/* {file.name.slice(file.name.indexOf("_") + 1)} ( */}{" "}
{file.name}( ({bytesToSize(file.size)})
{files && Array.isArray(files) && (
<ul>
{files.map((file, i) => (
<div
key={file.name}
className="govuk-!-margin-bottom-5 fileThumb"
>
<img
src={getThumbnailIcon(file, file.type)}
alt={file.name}
width="50"
/>
<span className="govuk-body govuk-!-font-size-14 govuk-!-padding-left-5">
{/* {file.name.slice(file.name.indexOf("_") + 1)} ( */}{" "}
{file.name}( ({bytesToSize(file.size)})
</span>
</div>
))}
</ul>
)}
{blobList.map((blob, i) => (
<div
key={blob.name + "_" + i}
className="govuk-!-margin-bottom-5 fileThumb govuk-!-margin-top-5"
>
<div className="">
<span
className="govuk-summary-list__actionLink watched_link govuk-!-margin-right-5 govuk-!-text-align-left"
onClick={() => {
deleteThisBlob(
field.containerID,
blob.name,
blob.hasheddeletepath,
blob.hashgetblobs,
field.ticketnumber
);
}}
title="Remove this file"
>
&minus;
</span>
</div>
))}
</ul>
)}
{blobList.map((blob, i) => (
<div
key={blob.name + "_" + i}
className="govuk-!-margin-bottom-5 fileThumb govuk-!-margin-top-5"
>
<div className="">
<span
className="govuk-summary-list__actionLink watched_link govuk-!-margin-right-5 govuk-!-text-align-left"
onClick={() => {
deleteThisBlob(
field.containerID,
blob.name,
blob.hasheddeletepath,
blob.hashgetblobs,
field.ticketnumber
);
}}
title="Remove this file"
<img
src={getThumbnailIconByExtension(blob.name)}
alt={blob.name}
width="50"
/>
<Link
key={i}
scroll={false}
href={
"/api/file/downloadblob?container=" +
field.containerID +
"&casefolderID=" +
field.ticketnumber +
"&blobname=" +
blob.name +
blob.hashedfilepath
}
className="govuk-body govuk-!-font-size-14 govuk-!-padding-left-5 govuk-link"
>
&minus;
</span>
{blob.name.slice(blob.name.indexOf("_") + 1)}(
{bytesToSize(blob.contentLength)})
</Link>
</div>
<img
src={getThumbnailIconByExtension(blob.name)}
alt={blob.name}
width="50"
/>
<Link
key={i}
scroll={false}
href={
"/api/file/downloadblob?container=" +
field.containerID +
"&casefolderID=" +
field.ticketnumber +
"&blobname=" +
blob.name +
blob.hashedfilepath
}
className="govuk-body govuk-!-font-size-14 govuk-!-padding-left-5 govuk-link">
{blob.name.slice(blob.name.indexOf("_") + 1)}({bytesToSize(blob.contentLength)})
</Link>
</div>
))}{" "}
</>;
))}{" "}
</>
);
};
+6
View File
@@ -24,6 +24,7 @@ const RenderTextfield = ({
meta: { touched, error },
...custom
}) => {
console.log(custom);
return (
<>
<div
@@ -53,6 +54,10 @@ const RenderTextfield = ({
id={id}
type={type}
disabled={disabled ? true : false}
maxLength={
custom.hasOwnProperty("maxFieldLength") &&
custom.maxFieldLength
}
/>
</div>
</>
@@ -469,6 +474,7 @@ let AboutYou = (props) => {
className="govuk-input govuk-input--width-20"
validate={[required]}
label={t("newappeal:about-you-on-behalf-label")}
maxFieldLength="25"
/>
<div className="govuk-form-group">
<details className="govuk-details" data-module="govuk-details">
+19
View File
@@ -10,6 +10,7 @@ import {
PickList,
Radiofield,
ReadOnlyfield,
RichMultiLinefield,
Textfield,
YesNofield,
} from "../elements";
@@ -114,6 +115,7 @@ export default function BuildField(props) {
parentFieldShowOnValue={props.parentFieldShowOnValue}
validation={props.validation}
hint={props.hint}
maxFieldLength={props.maxFieldLength}
/>
);
break;
@@ -142,6 +144,21 @@ export default function BuildField(props) {
parentField={props.parentField}
parentFieldShowOnValue={props.parentFieldShowOnValue}
validation={props.validation}
maxFieldLength={props.maxFieldLength}
/>
);
break;
case "{E0DECE4B-6666-4a8f-A065-082708572369}":
return (
<RichMultiLinefield
name={props.datafieldname}
label={props.label}
form={props.props.props.form}
formProps={props.props.props.props.form}
parentField={props.parentField}
parentFieldShowOnValue={props.parentFieldShowOnValue}
validation={props.validation}
maxFieldLength={props.maxFieldLength}
/>
);
break;
@@ -155,6 +172,7 @@ export default function BuildField(props) {
validation={props.validation}
parentField={props.parentField}
parentFieldShowOnValue={props.parentFieldShowOnValue}
maxFieldLength={props.maxFieldLength}
/>
);
break;
@@ -168,6 +186,7 @@ export default function BuildField(props) {
validation={props.validation}
parentField={props.parentField}
parentFieldShowOnValue={props.parentFieldShowOnValue}
maxFieldLength={props.maxFieldLength}
/>
);
break;
+5
View File
@@ -36,6 +36,7 @@ export default function BuildRow(props) {
var rows = xpath.select("//label/@description", doc);
var fieldtype = xpath.select("//@classid", doc);
var validation = xpath.select("//@validation", doc);
var maxFieldLength = xpath.select("//@maxFieldLength", doc);
var datafieldname = xpath.select("//@datafieldname", doc);
var datafieldcontent = xpath.select(
"//@datafieldcontent",
@@ -73,6 +74,9 @@ export default function BuildRow(props) {
? validation[0].value
: [];
maxFieldLength =
!_.isEmpty(maxFieldLength) && maxFieldLength[0].value;
parentField =
!_.isEmpty(parentField) && parentField[0].value;
@@ -150,6 +154,7 @@ export default function BuildRow(props) {
requiredDocumentLabel={requiredDocumentLabel}
requiredDocumentValue={requiredDocumentValue}
validation={validation}
maxFieldLength={maxFieldLength}
dateStart={dateStart}
dateEnd={dateEnd}
setDocumentsList={props.props.setDocumentsList}
+56 -3
View File
@@ -15,7 +15,13 @@ import {
setNewAppealProgress,
} from "../../store/appealType/action";
import { getFormCollectionByID, getProgressObj } from "../utils";
import { updateCase, patchCase, uploadFiles, sendEmail } from "../../actions";
import {
updateCase,
patchCase,
uploadFiles,
sendEmail,
generateAppealPDF,
} from "../../actions";
import { FieldsTranslations } from "../elements";
import jsonpath from "jsonpath";
@@ -132,13 +138,60 @@ let BuildSection = (props) => {
) => {
let incidentId = props.appealType.caseReference.incidentid;
let updateBody = values || {};
let buildAppealFilesArray = [];
console.log("attached docs: - ", buildAppealFilesArray);
let filesUplaodObj = Object.keys(values)
.filter(function (k) {
return k.indexOf("pinswg_fileUpload") == 0;
})
.reduce(function (newData, k) {
newData[k] = values[k];
return newData;
}, {});
console.log(filesUplaodObj);
for (let key in filesUplaodObj) {
for (let j in filesUplaodObj[key]) {
buildAppealFilesArray.push({
"name": filesUplaodObj[key][j].name,
"size": filesUplaodObj[key][j].size,
});
}
}
console.log(buildAppealFilesArray);
Object.assign(values, { "filesList": buildAppealFilesArray });
setSavingStatus(useSaveStatus);
uploadAppealFiles(values);
props.setNewAppealProgress(
getProgressObj(formXML, titleList, mandatoryFieldsData, props)
console.log(
"\n////////////////////////\n appeal pdf payload",
values,
props.props.accountDetails.containerID,
props.appealType.caseReference.ticketnumber,
"\n////////////////////////\n"
);
let pdfObj = values;
Object.assign(pdfObj, {
"containerID": props.props.accountDetails.containerID,
"casefolderID": props.appealType.caseReference.ticketnumber,
});
generateAppealPDF(
pdfObj,
props.props.accountDetails.containerID,
props.appealType.caseReference.ticketnumber
),
props.setNewAppealProgress(
getProgressObj(formXML, titleList, mandatoryFieldsData, props)
);
let appTypeCollection = getFormCollectionByID(
props.appealType.appealTypeID
);
+49 -11
View File
@@ -22,6 +22,7 @@ import ReactPDF, {
Font,
} from "@react-pdf/renderer";
import _ from "lodash";
import Html from "react-pdf-html";
import { DOMParser, XMLSerializer } from "@xmldom/xmldom";
@@ -59,7 +60,11 @@ export const AppealRow_pdf = (props) => {
},
logoImage: { width: "200pt" },
questionBullet: { width: "5%", fontSize: 12 },
questionText: { width: "30%", fontSize: 12 },
questionText: {
width: "35%",
fontSize: 12,
marginRight: 5,
},
questionTextMid: { width: "80%", fontSize: 12 },
questionTextWide: { width: "95%", fontSize: 12, marginBottom: 5 },
questionAnswer: {
@@ -84,9 +89,8 @@ export const AppealRow_pdf = (props) => {
},
questionAnswerWide: {
color: "#757575",
width: "95%",
width: "100%",
fontSize: 12,
marginLeft: "5%",
border: 1,
borderColor: "#eee",
backgroundColor: "white",
@@ -182,7 +186,6 @@ export const AppealRow_pdf = (props) => {
case "{5B773807-9FB2-42db-97C3-7A91EFF8ADFF}":
return (
<View
wrap={false}
style={{
flexDirection: "row",
marginBottom: 10,
@@ -283,7 +286,46 @@ export const AppealRow_pdf = (props) => {
</View>
);
break;
case "{E0DECE4B-6666-4a8f-A065-082708572369}":
return (
<View
style={{
flexDirection: "column",
marginBottom: 10,
}}
>
<View
wrap={false}
style={{
flexDirection: "row",
marginBottom: 10,
}}
>
<Text
style={
styles.questionTextWide
}
>
{rows[0].value}
</Text>
</View>
<View
style={
styles.questionAnswerWide
}
>
<Html style={styles.richArea}>
{
props.props[
datafieldname[0]
.value
]
}{" "}
</Html>
</View>
</View>
);
break;
default:
return (
<View
@@ -297,12 +339,8 @@ export const AppealRow_pdf = (props) => {
{/* {FieldsTranslations(rows[0].value)} */}
{rows[0].value}
</Text>
<Text
style={
styles.questionAnswerWide
}
>
<Text style={styles.questionAnswer}>
{" "}
{
props.props[
datafieldname[0].value
@@ -61,7 +61,7 @@ const styles = StyleSheet.create({
},
questionAnswerWide: {
color: "#757575",
width: "95%",
width: "100%",
fontSize: 12,
marginLeft: "5%",
border: 1,
@@ -121,7 +121,7 @@ export const planningappeals78_pdf = ({ docProps }) => {
xmlStr = xmlStr.replace(/> <"/g, "><");
xmlStr = xmlStr.toString();
console.log(xmlStr);
//console.log(xmlStr);
const parser = new DOMParser();
var doc = parser.parseFromString(xmlStr, "text/xml");
@@ -177,74 +177,6 @@ export const planningappeals78_pdf = ({ docProps }) => {
/>
</View>
<View style={styles.section}>
<View
style={{
marginTop: 10,
fontFamily: "Helvetica-Bold",
}}
>
<Text style={{ fontSize: 14 }}>Case details</Text>
</View>
<View style={styles.sectionContainer}>
<View
wrap={false}
style={{
flexDirection: "row",
marginBottom: 10,
}}
>
<Text style={styles.questionBullet}>1.</Text>
<Text style={styles.questionText}>
{t(
"myrepresentations:s78-section-question-1"
)}
:
</Text>
<Text style={styles.questionAnswer}>
{values.caseRef}
</Text>
</View>
<View
wrap={false}
style={{
flexDirection: "row",
marginBottom: 10,
}}
></View>
<View
wrap={false}
style={{
flexDirection: "row",
marginBottom: 10,
}}
>
<Text style={styles.questionBullet}>3.</Text>
<Text style={styles.questionText}>
Site address/grid ref:
</Text>
<Text style={styles.questionAnswer}>
{values.siteAddress}
</Text>
</View>
<View
wrap={false}
style={{
flexDirection: "row",
marginBottom: 10,
}}
>
<Text style={styles.questionBullet}>4.</Text>
<Text style={styles.questionText}>
Case Type:
</Text>
<Text style={styles.questionAnswer}>
{appealTypeValue.value}
</Text>
</View>
</View>
</View>
{Object.keys(titles).map((key) => (
<View key={key}>
<View
@@ -305,12 +237,12 @@ export const planningappeals78_pdf = ({ docProps }) => {
}}
>
<Text style={styles.questionBullet}>11.</Text>
<Text style={styles.questionText}>
<Text style={styles.questionTextWide}>
List of attached files
</Text>
<View
style={[
styles.questionAnswer,
styles.questionAnswerWide,
{ flexDirection: "column" },
]}
>