Merged PR 926: hide reps button & add rich text for reps

hide reps button & add rich text for reps

Related work items: #7943
This commit is contained in:
Robert Bond
2022-10-12 11:24:00 +00:00
22 changed files with 531 additions and 79 deletions
+6
View File
@@ -1073,6 +1073,12 @@ export const patchCase = async (incidentid) => {
};
export const getCase = (incidentID) => {
// console.log(
// "////////////// ------" +
// BASE_URL +
// "/api/endpoint/getcase_api?incidentID=" +
// incidentID
// );
return axios
.get(BASE_URL + "/api/endpoint/getcase_api?incidentID=" + incidentID)
.then((res) => {
+1
View File
@@ -36,6 +36,7 @@ const Case = (props) => {
searchString={props.searchString}
incidentid={props.incidentid}
showMap={props.showMap}
showLoginCheck={props.showLoginCheck}
/>
<Documents
incidentid={props.incidentid}
+35 -13
View File
@@ -128,6 +128,7 @@ let MakeRepresentation = (props) => {
onHandleSubmit={onHandleSubmit}
currentView={currentView}
setSubmitBack={setSubmitBack}
props={props}
/>
);
break;
@@ -144,6 +145,7 @@ let MakeRepresentation = (props) => {
onHandleSubmit={onHandleSubmit}
currentView={currentView}
setSubmitBack={setSubmitBack}
props={props}
/>
);
break;
@@ -160,6 +162,7 @@ let MakeRepresentation = (props) => {
onHandleSubmit={onHandleSubmit}
currentView={currentView}
setSubmitBack={setSubmitBack}
props={props}
/>
);
break;
@@ -176,6 +179,7 @@ let MakeRepresentation = (props) => {
onHandleSubmit={onHandleSubmit}
currentView={currentView}
setSubmitBack={setSubmitBack}
props={props}
/>
);
break;
@@ -204,16 +208,18 @@ let MakeRepresentation = (props) => {
setRepresentationSubmit={setRepresentationSubmit}
currentView={currentView}
setSubmitBack={setSubmitBack}
props={props}
/>
);
}
};
const onHandleSubmit = (values) => {
console.log(
values.representationCapacity,
currentView.representationCapacity
);
// console.log(
// values,
// values.representationCapacity,
// currentView.representationCapacity
// );
// console.log(_.isEmpty(currentView.representationCapacity));
// console.log(
@@ -228,15 +234,22 @@ let MakeRepresentation = (props) => {
.replace(/(\band|[\s\-\+\(\)\,\&])/g, "")
.toLowerCase()
)
: setRepresentationSubmit(true);
: setRepresentationSubmit("true");
window.alert(`You submitted:\n\n${JSON.stringify(values, null, 2)}`);
};
const repForm = props.props.form;
// console.log(
// "waht is representationSubmit:",
// currentView.representationSubmit
// );
return (
<div>
<form onSubmit={handleSubmit(onHandleSubmit)}>
{representationSubmit == true ? (
{currentView.representationSubmit == "true" ? (
<RepCompleteSubmit
formObj={formObj}
capacityOptionsArr={capacityOptionsArr}
@@ -253,13 +266,22 @@ let MakeRepresentation = (props) => {
) : (
<>
{!session ? (
<button
className="govuk-button withChevron govuk-button-cta"
type="button"
onClick={() => signIn("email")}
>
Sign in to raise representation
</button>
<>
<div>
<p className="govuk-body">
Some text in here to explain about
raising a representation and why logging
in
</p>
</div>
<button
className="govuk-button withChevron govuk-button-cta"
type="button"
onClick={() => signIn("email")}
>
Sign in to raise representation
</button>
</>
) : (
<>
<h1 className="govuk-heading-l">
@@ -3,17 +3,20 @@ import { connect } from "react-redux";
import { useRouter } from "next/router";
import useTranslation from "next-translate/useTranslation";
import { Field, reduxForm, reset } from "redux-form";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import {
RenderPickList,
RenderTextfield,
RenderRadioList,
RenderMultiline,
RenderFileUpload,
} from "./representationElements";
import { useDropzone } from "react-dropzone";
import {
setRepresentationCapacity,
setRepresentationSubmit,
} from "../../../store/currentView/action";
// import {
// setRepresentationCapacity,
// setRepresentationSubmit,
// } from "../../../store/currentView/action";
const RepAppellant = (props) => {
let { t } = useTranslation();
@@ -28,11 +31,8 @@ const RepAppellant = (props) => {
currentView,
} = props;
const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
const files = acceptedFiles.map((file) => (
<li key={file.path}>
{file.path} - {file.size} bytes
</li>
));
// console.log(props);
return (
<div id="rep-appellant">
@@ -141,7 +141,6 @@ const RepAppellant = (props) => {
className="govuk-checkboxes__input"
id="documentBox"
name="documentBox"
value="email"
data-aria-controls="documentBox"
type="checkbox"
component={RenderTextfield}
@@ -174,25 +173,28 @@ const RepAppellant = (props) => {
}
id="conditional-documentBox"
>
<div className="govuk-form-group">
<section className="container">
<div
{...getRootProps({
className: "dropzone",
})}
>
<input {...getInputProps()} />
<p>
Drag and drop files here or
click to select files
</p>
</div>
<aside>
<h4>Files</h4>
<ul>{files}</ul>
</aside>
</section>
</div>
<h2 className="govuk-heading-s">
{props.label}{" "}
</h2>
<Field
name="repsFiles"
id="repsFiles"
component={RenderFileUpload}
className="govuk-input govuk-input--width-20"
//validate={[required]}
label={props.label}
errorMsg="Is required"
ticketnumber={props.caseReference}
documentTypeCode={
props.documentTypeCode
}
hint={props.hint}
fileList={props.fileList}
setFilesForAppeal={
props.setFilesForAppeal
}
containerID={props.containerID}
/>
</div>
</div>
</fieldset>
@@ -208,13 +210,13 @@ const RepAppellant = (props) => {
Continue
</button>
{/* <a
onClick={() => {
setRepresentationSubmit(false);
}}
className="govuk-button"
>
Continue
</a> */}
onClick={() => {
setRepresentationSubmit(true);
}}
className="govuk-button"
>
Continue ww
</a> */}
<a
onClick={() => {
setRepresentationCapacity();
@@ -39,10 +39,10 @@ const RepComplete = (props) => {
return (
<div id="rep-appellant">
<div className="govuk-grid-column-full">
<div className="govuk-grid-row">
<h2 className="govuk-heading-m ">
<div className="govuk-grid-row govuk-body">
<h1 className="govuk-heading-m ">
Submission of Representation
</h2>
</h1>
<p>
Thank you for submitting your representation(s) using
the Appeals Casework Portal.
@@ -45,8 +45,8 @@ const RepCompleteSubmit = (props) => {
) : (
<div id="rep-appellant">
<div className="govuk-grid-column-full">
<div className="govuk-grid-row">
<h2 className="govuk-heading-m ">Submit</h2>
<div className="govuk-grid-row govuk-body">
<h1 className="govuk-heading-m ">Submit</h1>
<p>
The gathering and subsequent processing of the
personal data supplied by you in this form, is
@@ -1,6 +1,13 @@
import { Field, reduxForm } from "redux-form";
import { Field, Fields, reduxForm } from "redux-form";
import router from "next/router";
import React, { useState } from "react";
import React, { useState, useMemo } from "react";
import useTranslation from "next-translate/useTranslation";
import jsonpath from "jsonpath";
import Dropzone, { useDropzone } from "react-dropzone";
import dynamic from "next/dynamic";
const ReactQuill = dynamic(() => import("react-quill"), { ssr: false });
import "react-quill/dist/quill.snow.css";
export const RenderRadioList = ({
datafieldname,
@@ -149,14 +156,40 @@ export const RenderMultiline = ({
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 (
<>
<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>
</>
);
@@ -192,3 +225,339 @@ export function MultiLinefield(props) {
</div>
);
}
const baseStyle = {
display: "flex",
flexDirection: "column",
alignItems: "center",
padding: "20px",
borderWidth: 2,
borderRadius: 2,
borderColor: "#eeeeee",
borderStyle: "dashed",
backgroundColor: "#fafafa",
color: "#bdbdbd",
transition: "border .3s ease-in-out",
};
const activeStyle = {
borderColor: "#2196f3",
};
const acceptStyle = {
borderColor: "#00e676",
};
const rejectStyle = {
borderColor: "#ff1744",
};
export const RenderFileUpload = (field) => {
const files = field.input.value;
let { t } = useTranslation();
const style = useMemo(
() => ({
...baseStyle,
// ...(isDragActive ? activeStyle : {}),
// ...(isDragAccept ? acceptStyle : {}),
// ...(isDragReject ? rejectStyle : {}),
}),
[]
// [isDragActive, isDragReject, isDragAccept]
);
const [filesList, setFilesList] = useState([]);
const thumbs = filesList.map((file) => (
<div key={file.name} className="govuk-!-margin-bottom-5 fileThumb">
<img src={file.preview} alt={file.name} width="50" /> -{" "}
<span className="govuk-body">
{file.name} ({file.size / 1024}kb)
</span>
</div>
));
function 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];
}
const getThumbnailIcon = (fileObj, fileType) => {
switch (fileType) {
case "text/html":
return "/assets/images/documenttypes/html.png";
break;
case "text/plain":
return "/assets/images/documenttypes/txt.png";
break;
case "application/msword":
return "/assets/images/documenttypes/doc.png";
break;
case "application/pdf":
return "/assets/images/documenttypes/pdf.png";
break;
case "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
return "/assets/images/documenttypes/docx.png";
break;
case "text/csv":
return "/assets/images/documenttypes/csv.png";
break;
case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
return "/assets/images/documenttypes/xlsx.png";
break;
case "application/zip":
return "/assets/images/documenttypes/zip.png";
break;
case "image/jpeg":
case "image/png":
return URL.createObjectURL(fileObj);
break;
default:
return "/assets/images/documenttypes/txt.png";
break;
}
};
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";
break;
default:
return "/assets/images/documenttypes/txt.png";
break;
}
};
const getDocumentType = (docCode) => {
switch (docCode) {
case "000001":
return "000001";
break;
case "000002":
return "000002";
break;
case "000003":
return "000003";
break;
case "000004":
return "000004";
break;
case "000005":
return "000005";
break;
case "000006":
return "000006";
break;
case "000007":
return "000007";
break;
case "000008":
return "000008";
break;
case "000009":
return "000009";
break;
case "000010":
return "000010";
break;
case "000011":
return "000011";
break;
case "000012":
return "000012";
break;
case "000013":
return "000013";
break;
case "000014":
return "000014";
break;
case "000015":
return "000015";
break;
default:
return "000000";
}
};
const filelistObj = field.fileList || {};
const blobList = jsonpath.query(
filelistObj,
"$..[?(@.documentType=='" + field.documentTypeCode + "')]"
);
const deleteThisBlob = async (
containerName,
blobName,
deleteblobhash,
getblobshash,
casefolderID
) => {
//console.log(containerName, blobName, deleteblobhash);
deleteBlob(containerName, blobName, deleteblobhash, casefolderID)
.then((data) => data)
.then(() => {
getFilesFromBlobHashed(
containerName,
getblobshash,
casefolderID
).then((newfilelist) => field.setFilesForAppeal(newfilelist));
});
};
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"
)}
</div>
<em>
(
{t(
"newappeal:new-appeal-fileupload-file-list-label"
)}
)
</em>
</div>
<aside>{thumbs}</aside>
</section>
</>
)}
</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} ({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>
<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
}
>
<a className="govuk-body govuk-!-font-size-14 govuk-!-padding-left-5 govuk-link">
{blob.name} ({bytesToSize(blob.contentLength)})
</a>
</Link>
</div>
))}{" "}
</>
);
};
@@ -294,7 +294,14 @@ const RepInterestedPartyPerson = (props) => {
</div>
<div className="govuk-grid-row">
<div className="govuk-button-group">
<Link href="/representation">
<button
type="submit"
className="govuk-button"
data-module="govuk-button"
>
Continue
</button>
{/* <Link href="/representation">
<a
onClick={() => {
setRepresentationSubmit(true);
@@ -303,7 +310,7 @@ const RepInterestedPartyPerson = (props) => {
>
Continue
</a>
</Link>
</Link> */}
<a
onClick={() => {
setRepresentationCapacity();
@@ -202,7 +202,14 @@ const RepLandOwner = (props) => {
</div>
<div className="govuk-grid-row">
<div className="govuk-button-group">
<Link href="/representation">
<button
type="submit"
className="govuk-button"
data-module="govuk-button"
>
Continue
</button>
{/* <Link href="/representation">
<a
onClick={() => {
setRepresentationSubmit(true);
@@ -211,7 +218,7 @@ const RepLandOwner = (props) => {
>
Continue
</a>
</Link>
</Link> */}
<a
onClick={() => {
setRepresentationCapacity();
+9 -4
View File
@@ -65,6 +65,9 @@ const CaseSummary = (props) => {
showMap,
} = props;
const { data: session, status } = useSession();
//console.log("session status:", status, session);
const noRepresentationLink = ["/dnsdetails", "/dns/[developmentName]"];
let setCaseQueryObj = props[currentType];
@@ -276,8 +279,12 @@ const CaseSummary = (props) => {
<div className="govuk-grid-row">
<div className="govuk-grid-column-full">
<div className="govuk-button-group">
{noRepresentationLink.includes(router.pathname) ==
true ? (
{props.currentView.caseReference.showreps ==
"false" ? (
""
) : noRepresentationLink.includes(
router.pathname
) == true ? (
""
) : (
<Link href="/myportal/representation">
@@ -706,8 +713,6 @@ const CaseSummary = (props) => {
);
}
const { data: session, status } = useSession();
//console.log("session status:", status, session);
return (
<>
{showDetailsBlock}
+2 -2
View File
@@ -4,7 +4,7 @@ import { useContext } from "react";
import useTranslation from "next-translate/useTranslation";
import Summary from "./case/representation";
const CaseSummary = (props) => {
const CaseRepresentation = (props) => {
let { t } = useTranslation();
const router = useRouter();
@@ -35,4 +35,4 @@ const CaseSummary = (props) => {
);
};
export default CaseSummary;
export default CaseRepresentation;
+3 -3
View File
@@ -547,11 +547,11 @@ const DNSSearchResults = (props) => {
}}
title="Stop watching this case"
>
&minus;
<span className="eye"></span>
</span>
) : (
<span
className="govuk-summary-list__actionLink"
className="govuk-summary-list__actionLink watchLink"
onClick={() => {
selectWatchedCase(
cookies.pinsUser,
@@ -565,7 +565,7 @@ const DNSSearchResults = (props) => {
}}
title="Watch this case"
>
+
<span className="eye"></span>
</span>
)}
</dd>
+2
View File
@@ -306,6 +306,8 @@ const SearchResults = (props) => {
item.incidentid,
"appealType":
item.pinswg_appealcasetype,
"showreps":
props.showLoginCheck,
});
}}
>
+1 -1
View File
@@ -51,7 +51,7 @@ export default function Search(props) {
myportal={myportal}
watchedCases={watchedCases}
isLinkedCase={isLinkedCase}
showLoginCheck
showLoginCheck={showLoginCheck}
/>
</div>
</div>
+1
View File
@@ -66,6 +66,7 @@
"react-idle-timer": "^4.6.4",
"react-leaflet": "^3.2.5",
"react-loading-overlay": "^1.0.1",
"react-quill": "^2.0.0",
"react-redux": "^7.2.6",
"react-xml-parser": "^1.1.8",
"redux-form": "^8.3.8",
+6 -1
View File
@@ -24,7 +24,12 @@ const hashAPIPath = (queryPath) => {
export default async function ApiProxy(req, res) {
var incidentID = req.query.incidentID;
var token = await getToken();
var queryUrl = "incidents(" + incidentID + ")?$select=ticketnumber,title";
var queryUrl =
"incidents(" +
incidentID +
")?$select=ticketnumber,title,pinswg_appealcasetype";
//console.log(WEBAPI_URL + queryUrl + hashAPIPath(queryUrl));
return axios
.get(
@@ -26,6 +26,8 @@ export default async function ApiProxy(req, res) {
loggedInUserId +
"&$count=true&$orderby=createdon desc";
//console.log(WEBAPI_URL + queryUrl + hashAPIPath(queryUrl));
return axios
.get(
WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
@@ -23,7 +23,7 @@ export default async function ApiProxy(req, res) {
var caseReference = req.query.caseReference.split("'").join("''");
var token = await getToken();
//console.log("the case:", caseReference);
//console.log("the case:", req.query, caseReference);
var queryUrl =
appealType +
@@ -33,7 +33,7 @@ export default async function ApiProxy(req, res) {
queryUrl = queryUrl + getSelectQuery(appealType);
//console.log("test:", queryUrl);
//console.log("test:", WEBAPI_URL + queryUrl + hashAPIPath(queryUrl));
return axios
.get(
+4 -2
View File
@@ -8,7 +8,7 @@ import CookieBanner from "../../components/cookieBanner";
import Footer from "../../components/footer";
import Header from "../../components/header";
const Home = (props) => {
const CaseHome = (props) => {
const { footerLinks, pages } = props;
let { t, lang } = useTranslation();
@@ -66,6 +66,7 @@ const Home = (props) => {
representationsObj={
props.searchResultsObj.representationsObj
}
showLoginCheck={props.showLoginCheck}
/>
</div>
<Footer footerLinks={footerLinks} />
@@ -88,7 +89,8 @@ const mapStateToProps = (state) => {
watchedCases: state.watchedCases,
myRepresentations: state.myRepresentations,
awaitingSubmission: state.awaitingSubmission,
showLoginCheck: process.env.SHOWLOGIN || false,
};
};
export default connect(mapStateToProps)(Home);
export default connect(mapStateToProps)(CaseHome);
+17 -1
View File
@@ -12,6 +12,8 @@ import {
getPersonalAccount,
getPortalModuleDetails,
getWatchedCases,
consoleLogger,
getCase,
} from "../../actions";
import { createContainer } from "../../actions/azurestorage";
import { getProviderConfig } from "../../actions/govgateway";
@@ -255,9 +257,23 @@ export const getServerSideProps = wrapper.getServerSideProps(
);
const getDetails = (resultsObj, detailsType) => {
//console.log(detailsType);
let detailsArr = [];
resultsObj = resultsObj.value;
if (detailsType == "myRepresentations") {
const repsObj = resultsObj.map((searchDetail, index) => {
detailsArr.push(
getCase(searchDetail["_pinswg_case_value"]).then((data) => {
return getPortalModuleDetails(
getFormCollectionByID(data.pinswg_appealcasetype)
.LogicalCollectionName,
data.ticketnumber
);
})
);
});
}
const detailsObj = resultsObj.map((searchDetail, index) => {
if (searchDetail.pinswg_appealcasetype == null) {
console.log(
+2 -2
View File
@@ -18,7 +18,7 @@ import { wrapper } from "../store/store";
import _ from "lodash";
const Home = (props) => {
const { footerLinks, pages, isLinkedCase } = props;
const { footerLinks, pages, isLinkedCase, showLoginCheck } = props;
let { t, lang } = useTranslation();
const router = useRouter();
@@ -106,7 +106,7 @@ const Home = (props) => {
searchString={props.search.searchString}
searchResultsObj={props.searchResultsObj}
isLinkedCase={isLinkedCase}
showLoginCheck
showLoginCheck={showLoginCheck}
/>
</div>
<Footer footerLinks={footerLinks} />
+6 -1
View File
@@ -4,7 +4,7 @@ const currentViewInitialState = {
currentView: {},
caseReference: {},
representationCapacity: {},
representationSubmit: null,
representationSubmit: "",
representationSubmitConfirmation: {},
linkedCaseReferences: {},
currentPage: 1,
@@ -33,6 +33,11 @@ export default function reducer(state = currentViewInitialState, action) {
...state,
representationCapacity: action.representationCapacity,
};
case currentViewActionTypes.SETREPRESENTATIONSUBMIT:
return {
...state,
representationSubmit: action.representationSubmit,
};
case currentViewActionTypes.SETREPRESENTATIONSUBMITCONFIRMATION:
return {
...state,