diff --git a/.env.local b/.env.local index 48877f7e..a086b470 100644 --- a/.env.local +++ b/.env.local @@ -1,5 +1,3 @@ - - ACCESS_TOKEN_ENDPOINT = https://login.microsoftonline.com/ //ESNR Tenant TENANT = a8d860de-d5e1-45af-8376-d93f02e6b502 @@ -45,10 +43,10 @@ RELAYPATH = "dev-pedw-hc" GOOGLE_TAG_MANAGER = GTM-T78CBC3 -SHOWLOGIN = "false" -SHOWREPRESENTATIONS = "false" -SHOWFILEUPLOAD = "false" -SHOWMAPS = "false" +SHOWLOGIN = "true" +SHOWREPRESENTATIONS = false +SHOWFILEUPLOAD = "true" +SHOWMAPS = "true" //BASIC_AUTH_CREDENTIALS = pinswg:password|pinswg2:password2 @@ -89,3 +87,13 @@ NEXTAUTH_URL=http://localhost:3000 NEXTAUTH_URL_INTERNAL=http://localhost:3000 DATABASE_URL=mysql://nextAuthAdmin:!Sky9fish1972@77.68.17.157:3306/nextauthDB?synchronise=true SECRET=SuperSecret + + +//Azure Storage Account + +AZURE_CLIENT_ID = $CLIENT_ID +AZURE_TENANT_ID = $TENANT +AZURE_CLIENT_SECRET = $CLIENT_SECRET + +AZURE_PEDW_STORAGE_ENDPOINT = https://pedwdev.blob.core.windows.net +AZURE_PEDW_CONTAINER = "pedwapplications" \ No newline at end of file diff --git a/actions/azurestorage.js b/actions/azurestorage.js new file mode 100644 index 00000000..bdcd8d78 --- /dev/null +++ b/actions/azurestorage.js @@ -0,0 +1,205 @@ +import { v4 as uuidv4 } from "uuid"; +import { BlobServiceClient, ContainerClient } from "@azure/storage-blob"; +import { + DefaultAzureCredential, + InteractiveBrowserCredential, + EnvironmentCredential, + ClientSecretCredential, +} from "@azure/identity"; +import { hashAPIPath } from "."; + +const STORAGE_PATH = process.env.AZURE_PEDW_STORAGE_ENDPOINT; +const STORAGE_CONTAINER = process.env.AZURE_PEDW_CONTAINER; + +export const createContainer = async (containerName) => { + const creds = new DefaultAzureCredential(); + + containerName = containerName.toLowerCase(); + + // console.log( + // "container name:", + // containerName, + // STORAGE_PATH + "/" + containerName + // ); + + const containerClient = new ContainerClient( + `${STORAGE_PATH}/${containerName}`, + creds + ); + + const blobServiceClient = new BlobServiceClient(`${STORAGE_PATH}`, creds); + + const createContainerResponse = await containerClient.createIfNotExists(); + // console.log( + // `Created container ${containerName} successfully`, + // createContainerResponse.requestId + // ); + + // console.log("Containers:"); + // for await (const container of blobServiceClient.listContainers()) { + // console.log(`- ${container.name}`); + // } + + return containerName; +}; + +export const getContainers = async () => { + const creds = new DefaultAzureCredential(); + const blobServiceClient = new BlobServiceClient(`${STORAGE_PATH}`, creds); + + console.log("Containers:"); + for await (const container of blobServiceClient.listContainers()) { + console.log(`- ${container.name}`); + } +}; + +export const getBlobs = async (containerName) => { + const creds = new DefaultAzureCredential(); + + const containerClient = new ContainerClient( + `${STORAGE_PATH}/${containerName}`, + creds + ); + + containerClient.createIfNotExists(); + + const blobObj = []; + for await (const blob of containerClient.listBlobsFlat({ + prefix: "files/", + })) { + let blobDocumentType = blob.name + .split("/")[1] + .slice(0, blob.name.split("/")[1].indexOf("_")); + + blobObj.push({ + "name": blob.name.split("/")[1], + "path": blob.name, + "documentType": blobDocumentType, + "versionId": blob.versionId, + "isCurrentVersion": blob.isCurrentVersion, + "contentLength": blob.properties.contentLength, + "contentType": blob.contentType, + "hashedfilepath": hashAPIPath( + "/api/file/downloadblob?container=" + + containerName.toLowerCase() + + "&blobname=" + + blob.name.split("/")[1] + ), + "hasheddeletepath": hashAPIPath( + "/api/file/deleteblob?container=" + + containerName.toLowerCase() + + "&blobname=" + + blob.name.split("/")[1] + ), + "hashgetblobs": hashAPIPath( + "/api/file/getbloblist?container=" + containerName.toLowerCase() + ), + }); + } + + return blobObj; +}; + +export const createBlob = async (formContent, containerName) => { + const creds = new DefaultAzureCredential(); + + const containerClient = new ContainerClient( + `${STORAGE_PATH}/${containerName}`, + creds + ); + + const content = JSON.stringify(formContent); + const blobName = + formContent.pinswg_name + "_" + new Date().getTime() + ".json"; + const blockBlobClient = containerClient.getBlockBlobClient(blobName); + + const uploadBlobResponse = await blockBlobClient.upload( + content, + Buffer.byteLength(content) + ); + + // console.log("Blobs:"); + // for await (const blob of containerClient.listBlobsByHierarchy("/")) { + // console.log(`- ${blob.name}`); + // } + + return formContent.pinswg_name; +}; + +export const deleteBlob = async (containerName, blobName) => { + const creds = new DefaultAzureCredential(); + + const options = { + deleteSnapshots: "include", // or 'only' + }; + + const containerClient = new ContainerClient( + `${STORAGE_PATH}/${containerName.toLowerCase()}`, + creds + ); + + const blockBlobClient = containerClient.getBlockBlobClient(blobName); + + await blockBlobClient.deleteIfExists(options); + + console.log(`deleted blob ${blobName}`); + + return { "deleted": blobName }; +}; + +export const uploadFile = async (formContent, containerName, foldername) => { + const creds = new DefaultAzureCredential(); + + const containerClient = new ContainerClient( + `${STORAGE_PATH}/${containerName}`, + creds + ); + + const files = formContent; + + //console.log(...formContent); + //console.log("files...", files, files.length); + + for (const prop in files) { + //console.log(`files[${prop}] = ${files[prop][0].size}`); + const blobName = "files/" + files[prop][0].fieldName; + const blockBlobClient = containerClient.getBlockBlobClient(blobName); + const uploadBlobResponse = await blockBlobClient.uploadFile( + files[prop][0].path, + files[prop].size + ); + console.log( + `Uploaded block blob ${files[prop][0].fieldName} successfully`, + uploadBlobResponse.requestId + ); + } +}; + +export const downloadFile = async (containerName, blobName) => { + //console.log.apply(containerName, blobName); + const creds = new DefaultAzureCredential(); + + const containerClient = new ContainerClient( + `${STORAGE_PATH}/${containerName}`, + creds + ); + + const blobClient = containerClient.getBlobClient("files/" + blobName); + const downloadedBlob = await blobClient.download(0); + + const downloaded = await streamToBuffer(downloadedBlob.readableStreamBody); + return downloaded; +}; + +const streamToBuffer = async (readableStream) => { + return new Promise((resolve, reject) => { + const chunks = []; + readableStream.on("data", (data) => { + chunks.push(data instanceof Buffer ? data : Buffer.from(data)); + }); + readableStream.on("end", () => { + resolve(Buffer.concat(chunks)); + }); + readableStream.on("error", reject); + }); +}; diff --git a/actions/govgateway.js b/actions/govgateway.js index cf03784f..0b6e2061 100644 --- a/actions/govgateway.js +++ b/actions/govgateway.js @@ -1,5 +1,5 @@ import axios from "axios"; -import { hashAPIPath } from "./"; +import { hashAPIPath, consoleLogger } from "./"; const configEndpoint = process.env.GG_PROVIDER_CONFIG_ENDPOINT; const ggClientID = process.env.GG_CLIENT_ID; @@ -87,7 +87,9 @@ export const getPortalLogin = (emailAddress, token) => { .get(WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), azureHeaders(token)) .then((res) => res.data) .catch((error) => { - console.log("thiserror", error); + console.log(consoleLogger(error)); + //console.log("thiserror", error); + return JSON.stringify(error); }); }; diff --git a/actions/index.js b/actions/index.js index a57b8827..aa3a0d01 100644 --- a/actions/index.js +++ b/actions/index.js @@ -3,7 +3,7 @@ import https from "https"; import CryptoJS from "crypto-js"; import HmacSHA256 from "crypto-js/hmac-sha256"; import { getFormCollection } from "../components/utils"; - +import { downloadFile } from "./azurestorage"; let BASE_URL; const port = parseInt(process.env.PORT, 10) || 3000; @@ -24,9 +24,17 @@ const WEBAPI_URL = process.env.RELAY_ROOT || "https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/"; -const agent = new https.Agent({ - rejectUnauthorized: false, -}); +export const consoleLogger = (err) => { + var errStr = + "///////\nServer Error " + + "\n" + + err.response.status + + " : " + + err.response.statusText + + "\n///////"; + + return errStr; +}; export const getToken = () => { return axios @@ -125,7 +133,6 @@ export const hashAPIPath = (queryPath) => { CryptoJS.enc.Hex.parse(WORDKEY) ); hashlink = hashlink.toString(CryptoJS.enc.Hex); - return (queryPath.indexOf("?") > -1 ? "&hash=" : "?hash=") + hashlink; }; @@ -1029,35 +1036,117 @@ export const createAccount = (formValues) => { }); }; -export const uploadFiles = (formValues) => { - var data = formValues; - var queryUrl = "/api/uploads"; - var config = { +export const uploadFiles = async (formValues, filesObj, uploadhash) => { + let files = filesObj; + + //console.log(formValues); + var formData = new FormData(); + formData.append("appealData", JSON.stringify(formValues)); + + // files.forEach((file) => formData.append("files", file)); + + for (let i = 0; i < files.length; i++) { + for (let j = 0; j < files[i].length; j++) { + console.log(files[i][j].name); + formData.append(files[i][j].name, files[i][j]); + } + } + + //console.log(formData); + + var queryUrl = "/api/file/upload"; + + const config = { method: "post", url: queryUrl, - data: data, + data: formData, + headers: { "content-type": "multipart/form-data" }, }; - // const config = { - // method: "post", - // url: queryUrl, - // data: data, - // headers: { "content-type": "multipart/form-data" }, - // onUploadProgress: (event) => { - // //console.log( - // `Current progress:`, - // Math.round((event.loaded * 100) / event.total) - // ); - // }, - // }; - //console.log(config); - return axios(config) + try { + const res = await axios(config); + return res.data; + } catch (error) { + console.log("this serror", error); + } +}; + +export const getFilesFromBlob = (containerName) => { + return axios + .get( + BASE_URL + + "/api/file/getbloblist?container=" + + containerName.toLowerCase() + + hashAPIPath( + "/api/file/getbloblist?container=" + + containerName.toLowerCase() + ) + ) .then((res) => { - //console.log("posted ", res.data); + //console.log("//////////----", res.data); return res.data; }) .catch((error) => { console.log("this serror", error); }); }; + +export const getFilesFromBlobHashed = (containerName, getblobshash) => { + return axios + .get( + BASE_URL + + "/api/file/getbloblist?container=" + + containerName.toLowerCase() + + getblobshash + ) + .then((res) => { + //console.log("//////////----", res.data); + return res.data; + }) + .catch((error) => { + console.log("this serror", error); + }); +}; + +export const deleteBlob = async (containerName, blobName, deleteblobhash) => { + try { + const res = await axios.get( + BASE_URL + + "/api/file/deleteblob?container=" + + containerName.toLowerCase() + + "&blobname=" + + blobName + + deleteblobhash + ); + return res.data; + } catch (error) { + console.log("this serror", error); + } +}; + +export const downloadBlob = (containerName, blobName) => { + return axios + .get( + BASE_URL + + "/api/file/downloadblob?container=" + + containerName.toLowerCase() + + "&blobname=" + + blobName, + { responseType: "blob" } + ) + .then((response) => { + console.log("Downloaded blob content:www"); + + res.setHeader( + "content-disposition", + "attachment; filename=" + blobName + ); + console.log("has downloaded"); + + return res.status(200).send(response.data); + }) + .catch((error) => { + console.log("this serror", error); + }); +}; diff --git a/components/elements/index.js b/components/elements/index.js index fc653a3c..8e18de07 100644 --- a/components/elements/index.js +++ b/components/elements/index.js @@ -14,6 +14,13 @@ import FileUpload from "../newappeal/fileupload"; import Dropzone, { useDropzone } from "react-dropzone"; import _ from "lodash"; import { connect, useDispatch } from "react-redux"; +import { + getFilesFromBlobHashed, + deleteBlob, + downloadBlob, +} from "../../actions"; +import { setFilesForAppeal } from "../../store/appealType/action"; +import Link from "next/link"; import { addYears, @@ -1057,7 +1064,7 @@ export function NumericField(props) { (showIfHasParentShowValue == parentField) != false && showIfHasParentShowValue; - console.log("parentField:", parentField, showIfHasParentShowValue); + //console.log("parentField:", parentField, showIfHasParentShowValue); return ( <> @@ -1126,7 +1133,7 @@ export function DecimalField(props) { (showIfHasParentShowValue == parentField) != false && showIfHasParentShowValue; - console.log("parentField:", parentField, showIfHasParentShowValue); + //console.log("parentField:", parentField, showIfHasParentShowValue); return ( <> @@ -1246,6 +1253,8 @@ export function FileUploadField(props) { ticketnumber={props.ticketnumber} documentTypeCode={props.documentTypeCode} hint={props.hint} + fileList={props.fileList} + setFilesForAppeal={props.setFilesForAppeal} /> ); @@ -1277,104 +1286,6 @@ const rejectStyle = { borderColor: "#ff1744", }; -// const RenderFileUpload2 = ({ -// id, -// className, -// rows, -// datafieldname, -// name, -// label, -// input, -// errorMsg, -// meta: { touched, errorStr }, -// ...custom -// }) => { -// const [files, setFiles] = useState([]); - -// const onDrop = useCallback((acceptedFiles, fileRejections, event) => { -// setFiles( -// acceptedFiles.map((file) => -// Object.assign(file, { -// preview: URL.createObjectURL(file), -// }) -// ) -// ); -// console.log(acceptedFiles); -// event.target[acceptedFiles]; -// console.log(event.target.files); -// }, []); - -// const onChange = useCallback((acceptedFiles, fileRejections, event) => { -// setFiles( -// acceptedFiles.map((file) => -// Object.assign(file, { -// preview: URL.createObjectURL(file), -// }) -// ) -// ); -// event.target.files[acceptedFiles]; -// console.log(event.target.files); -// }, []); - -// const { -// getRootProps, -// getInputProps, -// isDragActive, -// isDragAccept, -// isDragReject, -// } = useDropzone({ -// onDrop, -// onChange, -// }); - -// const style = useMemo( -// () => ({ -// ...baseStyle, -// ...(isDragActive ? activeStyle : {}), -// ...(isDragAccept ? acceptStyle : {}), -// ...(isDragReject ? rejectStyle : {}), -// }), -// [isDragActive, isDragReject, isDragAccept] -// ); - -// const thumbs = files.map((file) => ( -//
-// {file.name} -{" "} -// -// {file.name} ({file.size / 1024}kb) -// -//
-// )); - -// // clean up -// useEffect( -// () => () => { -// files.forEach((file) => URL.revokeObjectURL(file.preview)); -// }, -// [files] -// ); - -// const onChangeFile = (e) => { -// const { -// input: { onChange }, -// } = props; -// onChange(e.target.files[0]); -// }; -// return ( -//
-//
-//
-//
-// -//
Drag and drop your images here.
-//
-//
{" "} -// -// {touched && errorStr && {errorStr}} -//
-// ); -// }; - const RenderFileUpload = (field) => { const files = field.input.value; let { t } = useTranslation(); @@ -1437,11 +1348,54 @@ const RenderFileUpload = (field) => { 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) => { - console.log(docCode); switch (docCode) { case "000001": return "000001"; @@ -1493,6 +1447,30 @@ const RenderFileUpload = (field) => { return "000000"; } }; + + const filelistObj = field.fileList || {}; + + const blobList = jsonpath.query( + filelistObj, + "$..[?(@.documentType=='" + field.documentTypeCode + "')]" + ); + + const deleteThisBlob = async ( + containerName, + blobName, + deleteblobhash, + getblobshash + ) => { + //console.log(containerName, blobName, deleteblobhash); + deleteBlob(containerName, blobName, deleteblobhash) + .then((data) => data) + .then(() => { + getFilesFromBlobHashed(containerName, getblobshash).then( + (newfilelist) => field.setFilesForAppeal(newfilelist) + ); + }); + }; + return ( <> { // } onDrop={(filesToUpload, e) => { - console.log(field.ticketnumber, field.documentTypeCode); const renamedAcceptedFiles = filesToUpload.map( (file) => new File( [file], - `${field.ticketnumber}_${getDocumentType( - field.documentTypeCode - )}_${file.name}`, + `${getDocumentType(field.documentTypeCode)}_${ + file.name + }`, { type: file.type, } @@ -1519,14 +1496,14 @@ const RenderFileUpload = (field) => { > {({ getRootProps, getInputProps }) => ( <> - {field.hint != false && ( -
{t(field.hint)}
+ {/* {field.hint != false && ( +
ss{t(field.hint)}
)} -
+
*/}
{" "} - +
Drag and drop your files here.
@@ -1556,6 +1533,50 @@ const RenderFileUpload = (field) => { ))} )} + {blobList.map((blob, i) => ( +
+
+ { + deleteThisBlob( + field.ticketnumber, + blob.name, + blob.hasheddeletepath, + blob.hashgetblobs + ); + }} + title="Remove this file" + > + − + +
+ {blob.name} + + + {blob.name} ({bytesToSize(blob.contentLength)}) + + +
+ ))}{" "} ); }; diff --git a/components/myportal.js b/components/myportal.js index 9d0a9fcf..fa2dfde8 100644 --- a/components/myportal.js +++ b/components/myportal.js @@ -21,7 +21,7 @@ const MyPortal = (props) => { const { locale } = router; const handleLogout = () => { - console.log("////////////", "\n", "logout", "\n", "//////////"); + console.log("////////////\n" + "logout" + "\n////////////"); destroyCookie({}, "pinsUser"), window.localStorage.clear(), //router.replace(props.ggLogout); diff --git a/components/myportal/uploadFile.js b/components/myportal/uploadFile.js index e3c560a1..45a82ccf 100644 --- a/components/myportal/uploadFile.js +++ b/components/myportal/uploadFile.js @@ -8,6 +8,7 @@ import { Field, reduxForm } from "redux-form"; import { connect } from "react-redux"; import Dropzone, { useDropzone } from "react-dropzone"; import { uploadFiles } from "../../actions"; +import { getContainers } from "../../actions/azurestorage"; const required = (errorMsg) => (value) => value || typeof value === "number" ? undefined : errorMsg; @@ -158,6 +159,60 @@ const RenderFileUpload = (field) => { 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"; + } + }; + return (
{ // } onDrop={(filesToUpload, e) => { + console.log(field.ticketnumber, field.documentTypeCode); const renamedAcceptedFiles = filesToUpload.map( (file) => - new File([file], `${file.name}_${+new Date()}`, { - type: file.type, - }) + new File( + [file], + `${field.ticketnumber}_${getDocumentType( + field.documentTypeCode + )}_${file.name}`, + { + type: file.type, + } + ) ); field.input.onChange(renamedAcceptedFiles); - console.log(renamedAcceptedFiles); }} > {({ getRootProps, getInputProps }) => ( @@ -221,7 +282,7 @@ const RenderFileUpload = (field) => { let UploadFile = (props) => { let { t } = useTranslation(); //const [showSpinnerState, setShowSpinnerState] = useState(false); - const { handleSubmit, pristine, reset, submitting } = props; + const { handleSubmit, pristine, reset, submitting, formContent } = props; const router = useRouter(); const { locale } = router; @@ -229,8 +290,19 @@ let UploadFile = (props) => { const onHandleSubmit = async (values) => { //spinnerState(); console.log(values); + console.log(formContent); + // getContainers(); - const uploadAction = await uploadFiles(values); + var dataObj = Object.assign(values, formContent); + var fileObj = dataObj.fileList; + + delete dataObj.fileList; + + const uploadAction = await uploadFiles(dataObj, fileObj).then( + (data) => { + console.log("hello", data); + } + ); // router.push({ // pathname: // router.locale == "cy" @@ -270,6 +342,7 @@ let UploadFile = (props) => { type="text" aria-describedby="caseReference-hint" hint1="Case Reference" + value="CAS-00764-L0Q9W2" />
@@ -281,6 +354,7 @@ let UploadFile = (props) => { //validate={[required]} label={props.label} errorMsg="Is required" + ticketnumber="CAS-00764-L0Q9W2" />
@@ -306,6 +380,69 @@ const mapStateToProps = (state) => { watchedCases: state.watchedCases, myRepresentations: state.myRepresentations, awaitingSubmission: state.awaitingSubmission, + formContent: { + "pinswg_caserecovered": "No", + "pinswg_siteaddresspostcode": "Site Address Postcode", + "pinswg_inspectorneededonsite": "Yes", + "pinswg_sitewithingreenbelt": "No", + "pinswg_siteaddressline2": "Site Address Line 2", + "pinswg_siteaddressline1": "Site Address Line 1", + "pinswg_s106unilateralsubmitted": "No", + "modifiedon": "2022-06-28T13:11:34Z", + "pinswg_developmentaffectsettingofalisted": "No", + "pinswg_planningappeals78id": + "57b533aa-43f1-ec11-aade-00224800be9c", + "pinswg_name": "CAS-00764-L0Q9W2", + "pinswg_whyisinspectorneededonsite": "to be nosey", + "pinswg_sitewithinsssi": "No", + "pinswg_healthandsafetyissuesonsite": "No", + "pinswg_developmentdescriptionchanged": "Yes", + "_stageid_value": "126e9c46-d51c-4623-aabf-aa30b34bfa54", + "traversedpath": "126e9c46-d51c-4623-aabf-aa30b34bfa54", + "createdon": "2022-06-21T09:22:29Z", + "timezoneruleversionnumber": 0, + "processid": "e4f065a6-157e-42f9-963a-9292d5041509", + "pinswg_priornotificationpriorapproval": "No", + "pinswg_predeterminedindicator": "No", + "pinswg_protectedspecies": "No", + "versionnumber": 912609, + "pinswg_siteaddresscounty": "Site Address County", + "pinswg_procedure": 846040000, + "pinswg_dateoflpadecision": "2022-06-22T23:00:00Z", + "pinswg_eiarequired": "No", + "pinswg_costappliedforindicator": "No", + "pinswg_areaofsiteinhectaresdec": 22, + "pinswg_detailedeiascreeningrequired": "No", + "pinswg_casepublishflag": "No", + "pinswg_siteaddresstown": "Site Address Town", + "utcconversiontimezonecode": 85, + "pinswg_caseworkreason": 846040005, + "pinswg_ownershipcertificate": 846040002, + "pinswg_lpadecisiononapplicationmade": "Yes", + "pinswg_floorspaceinsquaremeters": 111, + "_modifiedby_value": "149b3e11-5206-ec11-aac8-00224800be9c", + "pinswg_dateofapplication": "2022-06-20T23:00:00Z", + "pinswg_incarelatestoca": "No", + "_createdby_value": "149b3e11-5206-ec11-aac8-00224800be9c", + "pinswg_additionalappealsmade": "No", + "statuscode": 1, + "pinswg_siteviewablefromroad": "Yes", + "_pinswg_localplanningauthority_value": + "744c69f4-48da-eb11-aac5-00224800be9c", + "pinswg_lpaapplicationreference": "11111weweqweqwe", + "pinswg_recovered": "No", + "statecode": 0, + "pinswg_isfloodingandissue": "No", + "pinswg_isthesitewithinanaonb": "No", + "_organizationid_value": "01191a4d-105f-eb11-aaba-00224800be9c", + "pinswg_developmentdescription": "something to go here", + "pinswg_agriculturalholding": 846040000, + "_pinswg_planningappeals78ids_value": + "50b533aa-43f1-ec11-aade-00224800be9c", + }, + initialValues: { + caseReference: "CAS-00764-L0Q9W2", + }, }; }; @@ -320,5 +457,6 @@ export default connect( reduxForm({ form: "uploadFileForm", destroyOnUnmount: false, + enableReinitialize: true, // this is needed!! })(UploadFile) ); diff --git a/components/newappeal/buildCheckfield.js b/components/newappeal/buildCheckfield.js index 6e34ec66..1fdef5df 100644 --- a/components/newappeal/buildCheckfield.js +++ b/components/newappeal/buildCheckfield.js @@ -39,7 +39,7 @@ export default function BuildField(props) { case "{07FAC785-CD58-4f9f-ABB3-4B7DDC6ED5ED}": return <>{fieldValue}; break; - case "{ 4273EDBD-AC1D-40d3-9FB2-095C621B552D}": + case "{4273EDBD-AC1D-40d3-9FB2-095C621B552D}": return <>{fieldValue}; break; case "{5B773807-9FB2-42db-97C3-7A91EFF8ADFF}": @@ -58,8 +58,12 @@ export default function BuildField(props) { case "{C3EFE0C3-0EC6-42be-8349-CBD9079DFD8E}": return <>{fieldValue}; break; + case "{16D63FD6-119B-4353-BDCA-18358721C3FE}": + return <> docs {fieldValue}; + break; + default: - return <>{fieldValue}; + return <>ss{fieldValue}; } }; diff --git a/components/newappeal/buildcheckrow.js b/components/newappeal/buildcheckrow.js index 09d0a6b5..41723f6d 100644 --- a/components/newappeal/buildcheckrow.js +++ b/components/newappeal/buildcheckrow.js @@ -95,6 +95,28 @@ let BuildCheckRow = (props) => { "')]" ); + // if (datafieldname[0].value.indexOf("fileUpload") > 0) { + // isRequiredField.push({ + // "LogicalName": datafieldname[0].value, + // "RequiredLevel": { + // "Value": "Recommended", + // "CanBeChanged": true, + // "ManagedPropertyLogicalName": + // "canmodifyrequirementlevelsettings", + // }, + // "MetadataId": + // "32a7e6fc-4283-eb11-aac0-00224800be9c", + // }); + // } + + // console.log( + // datafieldname[0].value.indexOf("fileUpload") > 0, + // isRequiredField, + // props.props.form["appealForm"].values[ + // datafieldname[0].value + // ] + // ); + if ( typeof props.props.form["appealForm"].values[ datafieldname[0].value @@ -147,6 +169,9 @@ let BuildCheckRow = (props) => { datafieldname[0].value ] ) + : fieldtype[0].value == + "{16D63FD6-119B-4353-BDCA-18358721C3FE}" + ? "ssss" : props.props.form["appealForm"] .values[ datafieldname[0].value diff --git a/components/newappeal/buildchecksection.js b/components/newappeal/buildchecksection.js index 68137f51..f1617f87 100644 --- a/components/newappeal/buildchecksection.js +++ b/components/newappeal/buildchecksection.js @@ -28,6 +28,7 @@ let BuildCheckSection = (props) => { handleSubmit, formTitle, setCurrentSection, + updateCurrentSection, mandatoryFieldsData, } = props; @@ -55,6 +56,62 @@ let BuildCheckSection = (props) => { // /searchresults }; + const onHandleSubmit = (values) => { + //alert(1); + //updateCaseProgress(values); + // setCurrentSection(9999); + + alert(1); + }; + + 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 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; + } + }; + return (
@@ -80,7 +137,50 @@ let BuildCheckSection = (props) => {
))} -
+
+
+
+ {_.has(props.props.appealType.fileList.files) && + props.props.appealType.fileList.files.length > 0 + ? props.props.appealType.fileList.files.map( + (blob, i) => ( +
+ {blob.name} + + + {blob.name} ( + {bytesToSize( + blob.contentLength + )} + ) + +
+ ) + ) + : ""} +
+
+ { + updateCurrentSection(sectionCount); + }} + > + {t("newappeal:change-link-label")} + +
+
+
{ setCurrentSection: (currentSection) => { dispatch(setCurrentSection(currentSection)); }, + updateCurrentSection: (whichSection) => { + dispatch(setCurrentSection(whichSection)); + dispatch(setFormComplete("true")); + }, }; }; diff --git a/components/newappeal/buildfield.js b/components/newappeal/buildfield.js index 508807bb..33dab549 100644 --- a/components/newappeal/buildfield.js +++ b/components/newappeal/buildfield.js @@ -183,6 +183,12 @@ export default function BuildField(props) { } documentTypeCode={props.documentTypeCode} hint={props.hint} + fileList={ + props.props.props.props.appealType.fileList + } + setFilesForAppeal={ + props.props.props.setFilesForAppeal + } />
); diff --git a/components/newappeal/buildprogress.js b/components/newappeal/buildprogress.js index 7b752d01..38e6d3b1 100644 --- a/components/newappeal/buildprogress.js +++ b/components/newappeal/buildprogress.js @@ -5,6 +5,7 @@ import { connect } from "react-redux"; import xpath from "xpath"; import { setCurrentSection } from "../../store/appealType/action"; import { FieldsTranslations } from "../elements"; +import { getProgressObj } from "../utils"; const BuildProgress = (props) => { let { t } = useTranslation(); @@ -12,185 +13,23 @@ const BuildProgress = (props) => { const { locale } = router; const { + progObj, titleList, currentSection, documentListObj, formObjXML, mandatoryFieldsData, gotoSection, + setCurrentSection, } = 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; - typeof props.props.initialValues != "undefined" && - Object.keys(fieldObj).map((key, index) => { - fieldObj[key].datafieldname in props.props.initialValues && - props.props.initialValues[ - fieldObj[key].datafieldname - ] != null && - rowCount++; - }); - - return { - "title": titleList[key].value, - rowCount, - "totalFields": formObj[key].fieldsTotal, - "allFieldsComplete": rowCount == formObj[key].fieldsTotal, - }; - }); - - return progressObj; - }; - - const BuildRowObj = (rowXML, titleList) => { - const 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.query( - mandatoryFieldsData, - "$..value[?(@.LogicalName=='" + - datafieldname[0].value + - "')]" - ); - - if (datafieldname[0].value == "pinswg_fileUpload") { - 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, - "parentField": parentField, - "parentFieldShowOnValue": - parentFieldShowOnValue, - "key": key, - "picklistData": - props.props.formData.pickListData, - "mandatoryFieldsData": mandatoryFieldsData, - "hint": hint, - "requiredDocumentLabel": requiredDocumentLabel, - "requiredDocumentValue": requiredDocumentValue, - "validation": validation, - "dateStart": dateStart, - "dateEnd": dateEnd, - "setDocumentsList": - props.props.setDocumentsList, - "documentList": - props.props.appealType.documentList, - }; - } else { - return null; - } - } else { - return null; - } - } - } - }); - - rowObj = rowObj.filter(function (el) { - return el != null; - }); - - 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); + // const progObj = getProgressObj( + // formObjXML, + // titleList, + // mandatoryFieldsData, + // props + // ); return ( <> @@ -205,9 +44,82 @@ const BuildProgress = (props) => { {props.props.appealType.caseReference.ticketnumber} -
-
    + {/*
    */} + +
    + + {/*
      -
    +
*/} {Object.keys(documentListObj).length > 0 && ( diff --git a/components/newappeal/buildrow.js b/components/newappeal/buildrow.js index c4414367..946aeadf 100644 --- a/components/newappeal/buildrow.js +++ b/components/newappeal/buildrow.js @@ -157,6 +157,9 @@ export default function BuildRow(props) { props.props.appealType.documentList } documentTypeCode={documentTypeCode} + setFilesForAppeal={ + props.props.setFilesForAppeal + } /> ); // } else { diff --git a/components/newappeal/buildsection.js b/components/newappeal/buildsection.js index da9fb730..638c1b65 100644 --- a/components/newappeal/buildsection.js +++ b/components/newappeal/buildsection.js @@ -1,5 +1,5 @@ import Link from "next/link"; -import _, { has } from "lodash"; +import _, { has, last } from "lodash"; import { useRouter } from "next/router"; import useTranslation from "next-translate/useTranslation"; import { useState, useEffect } from "react"; @@ -11,18 +11,41 @@ import { setCaseReference, setCurrentSection, setDocumentsList, + setFilesForAppeal, + setNewAppealProgress, } from "../../store/appealType/action"; -import { getFormCollectionByID } from "../utils"; -import { updateCase, patchCase } from "../../actions"; +import { getFormCollectionByID, getProgressObj } from "../utils"; +import { updateCase, patchCase, uploadFiles } from "../../actions"; import { FieldsTranslations } from "../elements"; import jsonpath from "jsonpath"; import BuildProgress from "./buildprogress"; let BuildSection = (props) => { - // useEffect(() => { - // window.scrollTo(0, 0); - // }); + const [currentSectionSelected, setCurrentSectionSelected] = useState(1); + const [pickupWhereLeftOff, setPickupWhereLeftOff] = useState(true); + + useEffect(() => { + progObj = getProgressObj( + formXML, + titleList, + mandatoryFieldsData, + props + ); + // const lastIndex = progObj + // .map((whichIsLast) => whichIsLast.allFieldsComplete == true) + // .lastIndexOf(true); + + // setCurrentSection(currentSectionSelected + 1); + + // pickupWhereLeftOff == true && setCurrentSection(lastIndex + 1), + // setPickupWhereLeftOff(false); + + // // lastIndex != currentSectionSelected + // // ? (setCurrentSectionSelected(lastIndex), + // // setPickupWhereLeftOff(true)) + // // : setPickupWhereLeftOff(false); + }); let { t } = useTranslation(); @@ -67,12 +90,49 @@ let BuildSection = (props) => { doc ); + const progObj = getProgressObj( + formXML, + titleList, + mandatoryFieldsData, + props + ); + + const lastIndex = progObj + .map((whichIsLast) => whichIsLast.allFieldsComplete == true) + .lastIndexOf(true); + const handleParam = (setValue) => (e) => setValue(e.target.value); + const uploadAppealFiles = (values) => { + // get filelists from values object + let fileListObj = _.filter(values, function (v, key) { + return _.includes(key, "pinswg_fileUpload"); + }); + + //console.log(fileListObj); + + var dataObj = values; + + for (let key in dataObj) { + _.includes(key, "pinswg_fileUpload") == true && delete dataObj[key]; + } + + uploadFiles(dataObj, fileListObj).then((data) => { + //console.log("hello", data); + + return data; + }); + }; + const updateCaseProgress = (values) => { let incidentId = props.appealType.caseReference.incidentid; let updateBody = values || {}; + uploadAppealFiles(values); + props.setNewAppealProgress( + getProgressObj(formXML, titleList, mandatoryFieldsData, props) + ); + let appTypeCollection = getFormCollectionByID( props.appealType.appealTypeID ); @@ -118,8 +178,13 @@ let BuildSection = (props) => { }; const onHandleSubmit = (values) => { - //alert(1); - //updateCaseProgress(values); + //if (currentSection == sectionCount) { + let valuesObj = values || {}; + + delete valuesObj["_pinswg_appellant_value"]; + console.log("has errors:", props.invalid); + props.invalid == false && updateCaseProgress(valuesObj); + setCurrentSection(currentSection + 1); }; @@ -220,7 +285,22 @@ let BuildSection = (props) => { type="submit" className="govuk-button" data-module="govuk-button" - onClick={() => getErrors()} + onClick={() => { + getErrors(); + let valuesObj = _.has( + props1.props.form[props1.form], + "values" + ) + ? props.props.form[props.form].values + : {}; + + //console.log("valuesobj:", valuesObj); + + delete valuesObj["_pinswg_appellant_value"]; + + //console.log("on save:", valuesObj); + updateCaseProgress(valuesObj); + }} > {t("common:continue-button")} @@ -256,7 +336,11 @@ let BuildSection = (props) => {
+ {/* + Last section is {lastIndex} - {currentSection} + */} { mandatoryFieldsData={mandatoryFieldsData} currentSection={currentSection} initialValues={props.initialValues} + setCurrentSection={setCurrentSection} /> - {/* - - {Object.keys(documentListObj).length > 0 && ( -
-

- {t("newappeal:new-appeal-documentlist-nav")}: -

-
-
    -
      -
    • -
        - {Object.entries( - documentListObj - ).map(([key, value]) => { - return ( -
      1. {value}
      2. - ); - })} -
      -
    • -
    -
-
- )} */}