added in message queue for applications and reps

This commit is contained in:
2023-01-19 17:25:16 +00:00
parent 0c1de7d26b
commit d3bba6c620
16 changed files with 405 additions and 77 deletions
+3
View File
@@ -105,9 +105,12 @@ AZURE_CLIENT_ID = $CLIENT_ID
AZURE_TENANT_ID = $TENANT AZURE_TENANT_ID = $TENANT
AZURE_CLIENT_SECRET = $CLIENT_SECRET AZURE_CLIENT_SECRET = $CLIENT_SECRET
AZURE_STORAGE_ACCOUNT_NAME= "pedwdev" AZURE_STORAGE_ACCOUNT_NAME= "pedwdev"
AZURE_STORAGE_ACCOUNT_KEY = JS3ZIXianhYhB1lZrHB+bXbdzaLlON0alCyKrFAb+jVEwr9iqo2dty92EBxwnufNFM+CSN/fKX2R+AStDn0byg==
AZURE_PEDW_STORAGE_ENDPOINT = https://pedwdev.blob.core.windows.net AZURE_PEDW_STORAGE_ENDPOINT = https://pedwdev.blob.core.windows.net
AZURE_PEDW_CONTAINER = "pedwapplications" AZURE_PEDW_CONTAINER = "pedwapplications"
AZURE_PEDW_QUEUE_ENDPOINT = https://$AZURE_STORAGE_ACCOUNT_NAME.queue.core.windows.net
+136 -13
View File
@@ -1,4 +1,6 @@
import { v4 as uuidv4 } from "uuid"; import { DefaultAzureCredential } from "@azure/identity";
import _ from "lodash";
import { hashAPIPath } from ".";
const { const {
ContainerClient, ContainerClient,
BlockBlobClient, BlockBlobClient,
@@ -6,13 +8,25 @@ const {
BlobSASPermissions, BlobSASPermissions,
ContainerSASPermissions, ContainerSASPermissions,
generateBlobSASQueryParameters, generateBlobSASQueryParameters,
SASProtocol, SASProtocol,
} = require("@azure/storage-blob"); } = require("@azure/storage-blob");
import { DefaultAzureCredential } from "@azure/identity"; const {
import { consoleLogger, conLog, hashAPIPath } from "."; QueueServiceClient,
import _ from "lodash"; AccountSASResourceTypes,
AccountSASServices,
AccountSASPermissions,
QueueSASPermissions,
QueueSASSignatureValues,
generateAccountSASQueryParameters,
generateQueueSASQueryParameters,
StorageSharedKeyCredential,
QueueClient,
} = require("@azure/storage-queue");
const STORAGE_PATH = process.env.AZURE_PEDW_STORAGE_ENDPOINT; const STORAGE_PATH = process.env.AZURE_PEDW_STORAGE_ENDPOINT;
const STORAGE_CONTAINER = process.env.AZURE_PEDW_CONTAINER; const STORAGE_CONTAINER = process.env.AZURE_PEDW_CONTAINER;
const QUEUE_PATH = process.env.AZURE_PEDW_QUEUE_ENDPOINT;
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME; const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
export const createContainerSas = async (containerName) => { export const createContainerSas = async (containerName) => {
@@ -611,8 +625,6 @@ export const getProgressBlobs = async (containerName, caseReference) => {
}, },
]).reverse()[0]; ]).reverse()[0];
//console.log("blobObjwwwww:", blobObj);
return blobObj; return blobObj;
}; };
@@ -675,13 +687,124 @@ export const getRepslobs = async (containerName, caseReference) => {
blobObj.push(blob); blobObj.push(blob);
} }
// blobObj = _.sortBy(blobObj, [ //console.log("blobObjwwwww:", blobObj);
// function (o) {
// return o.lastModified;
// },
// ]).reverse()[0];
console.log("blobObjwwwww:", blobObj);
return blobObj; return blobObj;
}; };
export const createQueueSas = async (queueName) => {
// Get environment variables
const account = process.env.AZURE_STORAGE_ACCOUNT_NAME;
const accountKey = process.env.AZURE_STORAGE_ACCOUNT_KEY;
const sharedKeyCredential = new StorageSharedKeyCredential(
account,
accountKey
);
// Best practice: create time limits
const TEN_MINUTES = 10 * 60 * 1000;
const NOW = new Date();
// Best practice: set start time a little before current time to
// make sure any clock issues are avoided
const TEN_MINUTES_AFTER_NOW = new Date(NOW.valueOf() + TEN_MINUTES);
var resource_types = new AccountSASResourceTypes();
resource_types.container = true;
resource_types.object = true;
resource_types.service = true;
var permission = new QueueSASPermissions();
permission.read = true;
permission.write = true;
permission.delete = true;
permission.list = true;
permission.add = true;
permission.update = true;
permission.process = true;
var sas_signature_val = {
expiresOn: TEN_MINUTES_AFTER_NOW,
permissions: permission,
queueName: queueName,
};
const sasToken = generateQueueSASQueryParameters(
sas_signature_val,
sharedKeyCredential
);
//console.log("sass token:", sasToken);
return sasToken.toString();
};
export const createCaseCompleteMessage = async (
containerName,
caseReference
) => {
const whichQueue = "pedw-submitted-applications";
const queueToken = await createQueueSas(whichQueue);
const sasUrl = `${QUEUE_PATH}?${queueToken}`;
const queueServiceClient = new QueueServiceClient(sasUrl);
const message = {
containerName: containerName,
casepath:
containerName +
"/" +
caseReference +
"/" +
caseReference +
"_appeal.json",
casecontentpath: containerName + "/" + caseReference + "/case",
filespath: containerName + "/" + caseReference + "/files",
// uploadUrl: fileRecord.uploadUrl,
// filename: fileRecord.file.name,
// fileSize: fileRecord.file.size,
};
const sendMessageResponse = await queueServiceClient
.getQueueClient(whichQueue)
.sendMessage(
JSON.stringify(
`<QueueMessage><MessageText>${JSON.stringify(
message
)}</MessageText></QueueMessage>`
)
);
return sendMessageResponse;
};
export const createRepCompleteMessage = async (
containerName,
caseReference
) => {
const whichQueue = "pedw-submitted-representations";
const queueToken = await createQueueSas(whichQueue);
const sasUrl = `${QUEUE_PATH}?${queueToken}`;
const queueServiceClient = new QueueServiceClient(sasUrl);
const message = {
containerName: containerName,
caseref: caseReference,
reppath: containerName + "/" + caseReference + "/",
filespath: containerName + "/" + caseReference + "/files",
};
const sendMessageResponse = await queueServiceClient
.getQueueClient(whichQueue)
.sendMessage(
JSON.stringify(
`<QueueMessage><MessageText>${JSON.stringify(
message
)}</MessageText></QueueMessage>`
)
);
return sendMessageResponse;
};
+46
View File
@@ -1491,3 +1491,49 @@ export const getPortalLogin = (emailAddress) => {
return JSON.stringify(error); return JSON.stringify(error);
}); });
}; };
export const sendCaseCompleteMessage = async (containerID, caseReference) => {
var queryUrl =
"/api/file/createappealcompletemessage_api?container=" +
containerID +
"&tempcaseref=" +
caseReference;
var config = {
method: "get",
url: queryUrl,
};
//console.log(data);
return axios(config)
.then((res) => {
return res.data;
})
.catch((error) => {
//console.log("API call error", error);
});
};
export const sendRepCompleteMessage = async (containerID, caseReference) => {
var queryUrl =
"/api/file/createrepcompletemessage_api?container=" +
containerID +
"&tempcaseref=" +
caseReference;
var config = {
method: "get",
url: queryUrl,
};
//console.log(data);
return axios(config)
.then((res) => {
return res.data;
})
.catch((error) => {
//console.log("API call error", error);
});
};
+13
View File
@@ -19,6 +19,8 @@ import {
setRepresentationSubmit, setRepresentationSubmit,
setSubmitBack, setSubmitBack,
setRepresentationSubmitConfirmation, setRepresentationSubmitConfirmation,
setRepresentationMessageSent,
setRepresentationReset,
} from "../../../store/currentView/action"; } from "../../../store/currentView/action";
import RepCapacitySelection from "./representationCapacitySelection"; import RepCapacitySelection from "./representationCapacitySelection";
import RepDetails from "./representationDetails"; import RepDetails from "./representationDetails";
@@ -65,6 +67,7 @@ let MakeRepresentation = (props) => {
setSubmitBack, setSubmitBack,
handleSubmit, handleSubmit,
setRepresentationSubmitConfirmation, setRepresentationSubmitConfirmation,
setRepresentationMessageSent,
} = props; } = props;
const formObj = props.props.form; const formObj = props.props.form;
let setCaseQueryObj = props[currentType] || {}; let setCaseQueryObj = props[currentType] || {};
@@ -388,9 +391,13 @@ let MakeRepresentation = (props) => {
setRepresentationSubmit={setRepresentationSubmit} setRepresentationSubmit={setRepresentationSubmit}
currentView={currentView} currentView={currentView}
setSubmitBack={setSubmitBack} setSubmitBack={setSubmitBack}
setRepresentationMessageSent={
setRepresentationMessageSent
}
setRepresentationSubmitConfirmation={ setRepresentationSubmitConfirmation={
setRepresentationSubmitConfirmation setRepresentationSubmitConfirmation
} }
props={props}
/> />
) : ( ) : (
<> <>
@@ -453,6 +460,12 @@ const mapDispatchToProps = (dispatch) => {
setRepresentationSubmitConfirmation: () => { setRepresentationSubmitConfirmation: () => {
dispatch(setRepresentationSubmitConfirmation(true)); dispatch(setRepresentationSubmitConfirmation(true));
}, },
setRepresentationMessageSent: (messageSent) => {
dispatch(setRepresentationMessageSent(messageSent));
},
setRepresentationReset: () => {
dispatch(setRepresentationReset());
},
}; };
}; };
@@ -1,19 +1,11 @@
import useTranslation from "next-translate/useTranslation";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import useTranslation from "next-translate/useTranslation"; import { useEffect } from "react";
import { Field, reduxForm } from "redux-form";
import {
RenderPickList,
RenderTextfield,
RenderRadioList,
RenderMultiline,
} from "./representationElements";
import {
setRepresentationCapacity,
setRepresentationSubmit,
setSubmitBack,
} from "../../../store/currentView/action";
import { useDropzone } from "react-dropzone"; import { useDropzone } from "react-dropzone";
import { sendEmail, sendRepCompleteMessage } from "../../../actions";
import { setRepresentationReset } from "../../../store/currentView/action";
const RepComplete = (props) => { const RepComplete = (props) => {
let { t } = useTranslation(); let { t } = useTranslation();
@@ -28,6 +20,7 @@ const RepComplete = (props) => {
currentView, currentView,
setSubmitBack, setSubmitBack,
setRepresentationSubmitConfirmation, setRepresentationSubmitConfirmation,
setRepresentationMessageSent,
} = props; } = props;
const { acceptedFiles, getRootProps, getInputProps } = useDropzone(); const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
const files = acceptedFiles.map((file) => ( const files = acceptedFiles.map((file) => (
@@ -36,6 +29,28 @@ const RepComplete = (props) => {
</li> </li>
)); ));
useEffect(() => {
const reference = "PEDW-REPRESENTATION-COMPLETE";
const templateId = "c49785e7-3217-40b6-b33f-dffc4e58d5c1";
const emailAddress =
props.props.props.props.accountDetails.accountDetails.emailaddress1;
const personalisation = {
"caseReference":
props.props.currentView.caseReference.currentReference,
"emailAddress":
props.props.props.props.accountDetails.accountDetails
.emailaddress1,
"linkExpiry": 10 * 60,
};
props.props.currentView.representationMessageSent != true &&
(sendRepCompleteMessage(
props.props.props.props.accountDetails.containerID,
props.props.currentView.caseReference.currentReference
),
sendEmail(templateId, emailAddress, personalisation, reference),
setRepresentationMessageSent(true));
});
return ( return (
<div id="rep-appellant"> <div id="rep-appellant">
<div className="govuk-grid-column-full"> <div className="govuk-grid-column-full">
@@ -64,7 +79,12 @@ const RepComplete = (props) => {
<div className="govuk-grid-row"> <div className="govuk-grid-row">
<div className="govuk-button-group"> <div className="govuk-button-group">
<Link href="/myportal"> <Link href="/myportal">
<a className="govuk-button">Continue</a> <a
onClick={() => setRepresentationReset()}
className="govuk-button"
>
Continue
</a>
</Link> </Link>
</div> </div>
</div> </div>
@@ -1,22 +1,8 @@
import Link from "next/link"; import _ from "lodash";
import { useRouter } from "next/router";
import useTranslation from "next-translate/useTranslation"; import useTranslation from "next-translate/useTranslation";
import { Field, reduxForm } from "redux-form"; import { useRouter } from "next/router";
import {
RenderPickList,
RenderTextfield,
RenderRadioList,
RenderMultiline,
} from "./representationElements";
import {
setRepresentationCapacity,
setRepresentationSubmit,
setSubmitBack,
setRepresentationSubmitConfirmation,
} from "../../../store/currentView/action";
import { useDropzone } from "react-dropzone"; import { useDropzone } from "react-dropzone";
import RepComplete from "./representationComplete"; import RepComplete from "./representationComplete";
import _ from "lodash";
const RepCompleteSubmit = (props) => { const RepCompleteSubmit = (props) => {
let { t } = useTranslation(); let { t } = useTranslation();
@@ -31,6 +17,8 @@ const RepCompleteSubmit = (props) => {
currentView, currentView,
setSubmitBack, setSubmitBack,
setRepresentationSubmitConfirmation, setRepresentationSubmitConfirmation,
setRepresentationMessageSent,
setRepresentationReset,
} = props; } = props;
const { acceptedFiles, getRootProps, getInputProps } = useDropzone(); const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
const files = acceptedFiles.map((file) => ( const files = acceptedFiles.map((file) => (
@@ -44,7 +32,11 @@ const RepCompleteSubmit = (props) => {
return ( return (
<> <>
{currentView.representationSubmitConfirmation == true ? ( {currentView.representationSubmitConfirmation == true ? (
<RepComplete /> <RepComplete
props={props}
setRepresentationMessageSent={setRepresentationMessageSent}
setRepresentationReset={setRepresentationReset}
/>
) : ( ) : (
<div id="rep-appellant"> <div id="rep-appellant">
<div className="govuk-grid-column-full"> <div className="govuk-grid-column-full">
+23 -17
View File
@@ -1,27 +1,24 @@
import Link from "next/link";
import _ from "lodash";
import { useRouter } from "next/router";
import useTranslation from "next-translate/useTranslation"; import useTranslation from "next-translate/useTranslation";
import { setCurrentReference } from "../../store/currentView/action"; import Link from "next/link";
import { connect } from "react-redux"; import { useRouter } from "next/router";
import { parseCookies } from "nookies"; import { parseCookies } from "nookies";
import { connect } from "react-redux";
import { import {
getWatchedCasesProxy,
getPortalModuleDetailsProxy,
deleteWatchedCases,
deleteAwaitingSubmissions, deleteAwaitingSubmissions,
deleteWatchedCases,
getAwaitingSubmissionProxy, getAwaitingSubmissionProxy,
getPortalModuleDetailsProxy,
getWatchedCasesProxy,
} from "../../actions"; } from "../../actions";
import jsonpath from "jsonpath";
import transLookup from "../../data/lookuptranslations.json";
import {
setWatchedCases,
setWatchedCasesDetails,
} from "../../store/watchedCases/action";
import { import {
setAwaitingSubmission, setAwaitingSubmission,
setAwaitingSubmissionDetails, setAwaitingSubmissionDetails,
} from "../../store/awaitingSubmission/action"; } from "../../store/awaitingSubmission/action";
import { setCurrentReference } from "../../store/currentView/action";
import {
setWatchedCases,
setWatchedCasesDetails,
} from "../../store/watchedCases/action";
import { getFormCollectionByID } from "../utils"; import { getFormCollectionByID } from "../utils";
const TopThree = (props) => { const TopThree = (props) => {
@@ -139,8 +136,16 @@ const TopThree = (props) => {
<div className="cardModuleItem" key={index}> <div className="cardModuleItem" key={index}>
<div className="cardModuleDetails"> <div className="cardModuleDetails">
<div className="cardModuleReference"> <div className="cardModuleReference">
<b>Representation ID:</b> <b>Representation ID:</b>{" "}
<Link href="#"> <Link
// href={{
// pathname: "/myportal/representation",
// query: {
// case: showTopThreeArr[key].casereference,
// },
// }}
href="#"
>
<a <a
className="govuk-link--no-underline" className="govuk-link--no-underline"
data-id={index} data-id={index}
@@ -175,7 +180,8 @@ const TopThree = (props) => {
</Link> </Link>
</div> </div>
<div className="cardModuleReference"> <div className="cardModuleReference">
<b>{t("myportal:case-reference")}:</b>{" "} <b>{t("myportal:case-reference")}:</b>
{" "}
{showTopThreeArr[key].casereference} {showTopThreeArr[key].casereference}
</div> </div>
</div> </div>
+11 -11
View File
@@ -1,13 +1,15 @@
import jsonpath from "jsonpath";
import useTranslation from "next-translate/useTranslation"; import useTranslation from "next-translate/useTranslation";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { useEffect } from "react"; import { useEffect } from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { formValueSelector } from "redux-form"; import { formValueSelector } from "redux-form";
import xpath from "xpath"; import {
import { updateCase, patchCase, sendEmail } from "../../actions"; patchCase,
import data from "../../data/collections.json"; sendCaseCompleteMessage,
sendEmail,
updateCase,
} from "../../actions";
import { setCurrentSection } from "../../store/appealType/action"; import { setCurrentSection } from "../../store/appealType/action";
import { getFormCollectionByID } from "../utils"; import { getFormCollectionByID } from "../utils";
@@ -60,6 +62,11 @@ let CompleteAppeal = (props) => {
}; };
sendEmail(templateId, emailAddress, personalisation, reference); sendEmail(templateId, emailAddress, personalisation, reference);
sendCaseCompleteMessage(
props.appealType.caseReference.ticketnumber,
props.props.accountDetails.loggedinUserEmail
);
console.log("patching////////"); console.log("patching////////");
patchCase(incidentId); patchCase(incidentId);
}, [ }, [
@@ -135,13 +142,6 @@ let CompleteAppeal = (props) => {
<a className="govuk-link">Back to My Portal</a> <a className="govuk-link">Back to My Portal</a>
</Link> </Link>
</p> </p>
<p className="govuk-body">
<a href="#" className="govuk-link">
What did you think of this service?
</a>
(takes 30 seconds)
</p>
</div> </div>
</div> </div>
); );
+1
View File
@@ -12,6 +12,7 @@
"dependencies": { "dependencies": {
"@azure/identity": "^2.0.5", "@azure/identity": "^2.0.5",
"@azure/storage-blob": "^12.12.0", "@azure/storage-blob": "^12.12.0",
"@azure/storage-queue": "^12.11.0",
"@googlemaps/react-wrapper": "^1.1.24", "@googlemaps/react-wrapper": "^1.1.24",
"@magic-sdk/admin": "^1.4.0", "@magic-sdk/admin": "^1.4.0",
"@next-auth/prisma-adapter": "^1.0.4", "@next-auth/prisma-adapter": "^1.0.4",
+2
View File
@@ -8,6 +8,8 @@ export default async function ApiProxy(req, res) {
const notifyClient = new NotifyClient(process.env.NOTIFY_API_KEY); const notifyClient = new NotifyClient(process.env.NOTIFY_API_KEY);
//const emailReplyToId = process.env.EMAIL_REPLY_TO_ID; //const emailReplyToId = process.env.EMAIL_REPLY_TO_ID;
console.log("///////////////\n Sending email \ns//////////////");
notifyClient notifyClient
.sendEmail(data.templateId, data.emailAddress, { .sendEmail(data.templateId, data.emailAddress, {
personalisation: data.personalisation, personalisation: data.personalisation,
@@ -0,0 +1,37 @@
import { hashAPIPath } from "../../../actions";
import {
getBlobs,
createCaseCompleteMessage,
} from "../../../actions/azurestorage";
import nextConnect from "next-connect";
import middleware from "../middleware/middleware";
const ApiProxy = nextConnect();
ApiProxy.use(middleware);
ApiProxy.get(async (req, res) => {
var containerName = req.query.container;
var tempCaseRef = req.query.tempcaseref;
console.log("/////Create Case Message:\n", tempCaseRef, "\n//////////////");
// console.log(hashAPIPath(checkquerypath), checkHash);
// console.log(hashAPIPath(checkquerypath) == "&hash=" + checkHash);
//if (hashAPIPath(checkquerypath) == "&hash=" + checkHash) {
await createCaseCompleteMessage(containerName, tempCaseRef).then((data) => {
return res.status(200).json(data);
});
// } else {
// return res.status(400).json();
// }
});
export const config = {
api: {
bodyParser: false,
},
};
export default ApiProxy;
@@ -0,0 +1,41 @@
import { hashAPIPath } from "../../../actions";
import {
getBlobs,
createRepCompleteMessage,
} from "../../../actions/azurestorage";
import nextConnect from "next-connect";
import middleware from "../middleware/middleware";
const ApiProxy = nextConnect();
ApiProxy.use(middleware);
ApiProxy.get(async (req, res) => {
var containerName = req.query.container;
var tempCaseRef = req.query.tempcaseref;
console.log(
"/////Create Rep complete Message:\n",
tempCaseRef,
"\n//////////////"
);
// console.log(hashAPIPath(checkquerypath), checkHash);
// console.log(hashAPIPath(checkquerypath) == "&hash=" + checkHash);
//if (hashAPIPath(checkquerypath) == "&hash=" + checkHash) {
await createRepCompleteMessage(containerName, tempCaseRef).then((data) => {
return res.status(200).json(data);
});
// } else {
// return res.status(400).json();
// }
});
export const config = {
api: {
bodyParser: false,
},
};
export default ApiProxy;
+1 -1
View File
@@ -27,7 +27,7 @@ ApiProxy.get(async (req, res) => {
//if (hashAPIPath(checkquerypath) == "&hash=" + checkHash) { //if (hashAPIPath(checkquerypath) == "&hash=" + checkHash) {
const blobObj = await getRepslobs(containerName, casefolderID) const blobObj = await getRepslobs(containerName, casefolderID)
.then((data) => { .then((data) => {
console.log("ertyuikjhgfg", data); console.log("reps blob", data);
return downloadAllRepsFiles(containerName, data); return downloadAllRepsFiles(containerName, data);
}) })
+20
View File
@@ -8,6 +8,8 @@ export const currentViewActionTypes = {
SETCURRENTLINKEDCASES: "SETCURRENTLINKEDCASES", SETCURRENTLINKEDCASES: "SETCURRENTLINKEDCASES",
SETCURRENTPAGE: "SETCURRENTPAGE", SETCURRENTPAGE: "SETCURRENTPAGE",
SETSHOWREPS: "SETSHOWREPS", SETSHOWREPS: "SETSHOWREPS",
SETREPRESENTATIONMESSAGESENT: "SETREPRESENTATIONMESSAGESENT",
SETREPRESENTATIONRESET: "SETREPRESENTATIONRESET",
}; };
export const getCurrentViewObj = () => (dispatch) => { export const getCurrentViewObj = () => (dispatch) => {
@@ -60,6 +62,24 @@ export const setRepresentationSubmitConfirmation =
}); });
}; };
export const setRepresentationMessageSent =
(representationMessageSent) => (dispatch) => {
return dispatch({
type: currentViewActionTypes.SETREPRESENTATIONMESSAGESENT,
representationMessageSent: representationMessageSent,
});
};
export const setRepresentationReset = () => (dispatch) => {
return dispatch({
type: currentViewActionTypes.SETREPRESENTATIONRESET,
representationCapacity: {},
representationSubmit: "",
representationSubmitConfirmation: {},
representationMessageSent: false,
});
};
export const setCurrentLinkedCases = (linkedCaseReferences) => (dispatch) => { export const setCurrentLinkedCases = (linkedCaseReferences) => (dispatch) => {
return dispatch({ return dispatch({
type: currentViewActionTypes.SETCURRENTLINKEDCASES, type: currentViewActionTypes.SETCURRENTLINKEDCASES,
+15
View File
@@ -6,6 +6,7 @@ const currentViewInitialState = {
representationCapacity: {}, representationCapacity: {},
representationSubmit: "", representationSubmit: "",
representationSubmitConfirmation: {}, representationSubmitConfirmation: {},
representationMessageSent: false,
linkedCaseReferences: {}, linkedCaseReferences: {},
currentPage: 1, currentPage: 1,
showReps: false, showReps: false,
@@ -45,6 +46,20 @@ export default function reducer(state = currentViewInitialState, action) {
representationSubmitConfirmation: representationSubmitConfirmation:
action.representationSubmitConfirmation, action.representationSubmitConfirmation,
}; };
case currentViewActionTypes.SETREPRESENTATIONMESSAGESENT:
return {
...state,
representationMessageSent: action.representationMessageSent,
};
case currentViewActionTypes.SETREPRESENTATIONRESET:
return {
...state,
representationCapacity: {},
representationSubmit: "",
representationSubmitConfirmation: {},
representationMessageSent: false,
};
case currentViewActionTypes.SETCURRENTPAGE: case currentViewActionTypes.SETCURRENTPAGE:
return { return {
...state, ...state,
+12 -3
View File
@@ -12,10 +12,12 @@
@media screen and (min-width: 600px) and (max-width: 900px) { @media screen and (min-width: 600px) and (max-width: 900px) {
.card { .card {
flex-basis: 45.99%; flex-basis: 45.99%;
// Every card in the first row needs horizontal margin // Every card in the first row needs horizontal margin
&:nth-child(2n-1) { &:nth-child(2n-1) {
margin-right: 3%; margin-right: 3%;
} }
// Every card in the second row needs horizontal margin // Every card in the second row needs horizontal margin
&:nth-child(2n-2) { &:nth-child(2n-2) {
margin-left: 3%; margin-left: 3%;
@@ -40,6 +42,7 @@
&:nth-child(2n-2) { &:nth-child(2n-2) {
margin-left: 3%; margin-left: 3%;
} }
&.card-3 { &.card-3 {
flex-basis: 31.1%; flex-basis: 31.1%;
min-height: 300px; min-height: 300px;
@@ -87,15 +90,18 @@ html[data-useragent*="MSIE 10.0"] .flex-container {
*:last-child { *:last-child {
margin-bottom: 0; margin-bottom: 0;
} }
a, a,
a:active, a:active,
a:visited { a:visited {
color: $blue; color: $blue;
font-weight: bold; font-weight: bold;
text-decoration: none; text-decoration: none;
&:hover { &:hover {
color: $lightblue; color: $lightblue;
} }
&.govuk-button { &.govuk-button {
color: $white; color: $white;
// &:focus { // &:focus {
@@ -117,6 +123,7 @@ html[data-useragent*="MSIE 10.0"] .flex-container {
.card-heading a { .card-heading a {
color: $govuk-link-colour; color: $govuk-link-colour;
margin-top: 0; margin-top: 0;
&:focus { &:focus {
color: govuk-colour("black", $legacy: "black"); color: govuk-colour("black", $legacy: "black");
outline: 3px solid transparent; outline: 3px solid transparent;
@@ -178,6 +185,7 @@ html[data-useragent*="MSIE 10.0"] .flex-container {
} }
} }
} }
&.clear { &.clear {
background-color: govuk-colour("white", $legacy: "white"); background-color: govuk-colour("white", $legacy: "white");
border: none; border: none;
@@ -252,12 +260,13 @@ div.cardModuleItem:last-of-type {
.cardModuleReference { .cardModuleReference {
display: flex; display: flex;
b { b {
min-width: 122px; min-width: 122px;
margin-right: 10px;
} }
a {
margin-left: 10px; a {}
}
} }
.cardModuleRemoveCase { .cardModuleRemoveCase {