Merged PR 1657: 17025 email notiofications fixes

17025 email notiofications fixes

Related work items: #17025
This commit is contained in:
Robert Bond
2025-06-05 17:08:47 +00:00
6 changed files with 287 additions and 35 deletions
+1
View File
@@ -61,6 +61,7 @@ const Header = (props) => {
"/myportal/representation", "/myportal/representation",
"/myportal/viewall", "/myportal/viewall",
"/contactus", "/contactus",
"/myportal/contactus",
"/unsubscribe/[watchlistid]", "/unsubscribe/[watchlistid]",
"/unsubscribeall/[watchlistid]", "/unsubscribeall/[watchlistid]",
]; ];
+21
View File
@@ -115,6 +115,27 @@ const TopThree = (props) => {
.then((data) => data) .then((data) => data)
.then(() => { .then(() => {
getWatchedCasesProxy(cookies.pinsUser).then((data) => { getWatchedCasesProxy(cookies.pinsUser).then((data) => {
let showWatchedCases = (submittedArr) => {
const required = submittedArr.value.filter((el) => {
return (
el.pinswg_representationsubmitted == null
);
});
let newObj = {};
return Object.assign(newObj, {
"@odata.count": required.length,
"value": required,
});
};
data = showWatchedCases(data);
data.value.sort(function compare(a, b) {
var dateA = new Date(a.createdon);
var dateB = new Date(b.createdon);
return dateB - dateA;
});
setWatchedCases(data), setWatchedCases(data),
getDetailsProxy(data, "myWatchedCases").then( getDetailsProxy(data, "myWatchedCases").then(
(data) => { (data) => {
+146 -6
View File
@@ -12,6 +12,8 @@ import {
getAwaitingSubmissionFromBlobProxy, getAwaitingSubmissionFromBlobProxy,
getRepsFromBlobProxy, getRepsFromBlobProxy,
getWatchedCasesProxy, getWatchedCasesProxy,
getWatchedCases,
createWatchedCases,
} from "../../actions"; } from "../../actions";
import { getDetailsProxy, getFormCollectionByID } from "../../components/utils"; import { getDetailsProxy, getFormCollectionByID } from "../../components/utils";
import transLookup from "../../data/lookuptranslations.json"; import transLookup from "../../data/lookuptranslations.json";
@@ -272,12 +274,21 @@ const ViewAllResults = (props) => {
/> />
{viewAllKey == "myRepresentations" && ( {viewAllKey == "myRepresentations" && (
<> <>
<br /> <span className="govuk-body govuk-!-font-size-14">
<span>
{resultsArr[key].representationType} {resultsArr[key].representationType}
</span> </span>
</> </>
)} )}
{viewAllKey == "mySubmittedReps" && (
<>
<span className="govuk-body govuk-!-font-size-14">
{item.pinswg_representationtype}{" "}
{formatDates(
item.pinswg_representationsubmitted
)}
</span>
</>
)}
</> </>
)} )}
</dd> </dd>
@@ -415,10 +426,15 @@ const ViewAllResults = (props) => {
{/* Helper function to extract address lines based on current view and data */} {/* Helper function to extract address lines based on current view and data */}
{[ {[
"pinswg_siteaddressline1", "pinswg_siteaddressline1",
"pinswg_addressline1",
"pinswg_siteaddressline2", "pinswg_siteaddressline2",
"pinswg_addressline2",
"pinswg_siteaddresstown", "pinswg_siteaddresstown",
"pinswg_addresstown",
"pinswg_siteaddresscounty", "pinswg_siteaddresscounty",
"pinswg_siteaddresspostcode", "pinswg_siteaddresspostcode",
"pinswg_postcode",
"pinswg_projectlocation",
].map((field, idx) => { ].map((field, idx) => {
const isAwaitingSubmission = const isAwaitingSubmission =
viewAllKey === "awaitingSubmissionDetails"; viewAllKey === "awaitingSubmissionDetails";
@@ -426,7 +442,7 @@ const ViewAllResults = (props) => {
viewAllKey === "myRepresentations"; viewAllKey === "myRepresentations";
const searchValue = _.get( const searchValue = _.get(
searchDetailsObj, searchDetailsObj,
`${key}.${field}` `${key}.${field} `
); );
const detailsValue = _.get(detailsObj, field); const detailsValue = _.get(detailsObj, field);
@@ -738,12 +754,15 @@ const ViewAllResults = (props) => {
)} )}
{viewAllKey == "watchedCases" && ( {viewAllKey == "watchedCases" && (
<dd className="govuk-summary-list__value govuk-!-font-size-16 cardModuleItem "> <dd
className="govuk-summary-list__value govuk-!-font-size-16 cardModuleItem govuk-!-font-size-14 govuk-summary-list__action"
style={{ display: "flex", flexDirection: "column" }}
>
<button <button
title={t( title={t(
"case:do-you-want-to-delete-case-label" "case:do-you-want-to-delete-case-label"
)} )}
className=" cardModuleRemoveCase govuk-link govuk-link--no-underline govuk-link--inverse " className=" govuk-summary-list__actionLink watched_link"
onClick={() => { onClick={() => {
confirm( confirm(
t( t(
@@ -761,13 +780,61 @@ const ViewAllResults = (props) => {
> >
&mdash; &mdash;
</button> </button>
{item.pinswg_emailnotifications == true ? (
<button
className="govuk-summary-list__actionLink mailLink watched_link"
title="Unsubscribe to email updates"
onClick={() => {
confirm(
" Do you want to unsubscribe to email updates for " +
item.pinswg_title +
"?"
) &&
selectEmailNotifications(
props.accountDetails
.accountDetails
.emailaddress1,
props.accountDetails
.loggedinUserId,
item._pinswg_watchedcase_value,
item.pinswg_appealcasetype,
null
);
}}
>
<span className="mailicon icon"></span>
</button>
) : (
<button
className="govuk-summary-list__actionLink mailLink"
title="Email about changes"
onClick={() => {
confirm(
" Do you want to be sent email updates for " +
item.pinswg_title +
"?"
) &&
selectEmailNotifications(
props.accountDetails
.accountDetails
.emailaddress1,
props.accountDetails
.loggedinUserId,
item._pinswg_watchedcase_value,
item.pinswg_appealcasetype,
true
);
}}
>
<span className="mailicon icon"></span>
</button>
)}
</dd> </dd>
)} )}
</div> </div>
); );
}); });
}; };
buildResultsRowArr();
const sortDataBy = (whichField) => { const sortDataBy = (whichField) => {
setOrderbyState(whichField); setOrderbyState(whichField);
@@ -861,6 +928,7 @@ const ViewAllResults = (props) => {
}); });
}); });
}; };
const deleteItem = (caseID, topThreeType) => { const deleteItem = (caseID, topThreeType) => {
let cookies = parseCookies(); let cookies = parseCookies();
//console.log("sssss", caseID, topThreeType); //console.log("sssss", caseID, topThreeType);
@@ -884,6 +952,78 @@ const ViewAllResults = (props) => {
}); });
}; };
const isEmailSignUp = (whichIncident) => {
let isEmail = jsonpath({
path:
"$[?(@ && @._pinswg_watchedcase_value=='" +
whichIncident +
"' && @.pinswg_emailnotifications==true)]",
json: resultsArr,
eval: true,
});
return isEmail;
};
const selectEmailNotifications = (
emailaddress,
loggedInUser,
incidentID,
appealType,
updateEmailNotifications
) => {
let updateBody = {
"pinswg_WatchedCase@odata.bind": "/incidents(" + incidentID + ")",
"pinswg_Contact@odata.bind": "/contacts(" + loggedInUser + ")",
"pinswg_appealcasetype": appealType,
"pinswg_emailnotifications": updateEmailNotifications,
};
console.log("Email signed up");
createWatchedCases(updateBody)
.then((data) => data)
.then(() => {
getWatchedCases(props.accountDetails.loggedinUserId).then(
(data) => {
let showWatchedCases = (submittedArr) => {
const required = submittedArr.value.filter((el) => {
return (
el.pinswg_representationsubmitted == null
);
});
let newObj = {};
return Object.assign(newObj, {
"@odata.count": required.length,
"value": required,
});
};
data = showWatchedCases(data);
data.value.sort(function compare(a, b) {
var dateA = new Date(a.createdon);
var dateB = new Date(b.createdon);
return dateB - dateA;
});
setWatchedCases(data);
getDetailsProxy(data, "myWatchedCases")
.then((data) => {
setWatchedCasesDetails(data);
})
.then(() => {
setCurrentView({
"viewName": "Watched Cases",
"viewKey": "watchedCases",
});
});
}
);
});
};
buildResultsRowArr();
return ( return (
<> <>
<div className="govuk-grid-row"> <div className="govuk-grid-row">
-1
View File
@@ -91,7 +91,6 @@ const RepsOnResults = (props) => {
return ( return (
<> <>
<br />
<br /> <br />
{(_.has(detailsObj, "pinswg_startdate") || {(_.has(detailsObj, "pinswg_startdate") ||
_.has(detailsObj, "pinswg_applicationacceptedasvalid") || _.has(detailsObj, "pinswg_applicationacceptedasvalid") ||
+92 -27
View File
@@ -1,14 +1,14 @@
/** // /**
* @swagger // * @swagger
* /api/endpoint/createmywatchedcases_api: // * /api/endpoint/createmywatchedcases_api:
* post: // * post:
* tags: [Portal,Case] // * tags: [Portal,Case]
* summary: Phase 2 // * summary: Phase 2
* description: Create my watched cases // * description: Create my watched cases
* responses: // * responses:
* 200: // * 200:
* description: Success // * description: Success
*/ // */
import axios from "axios"; import axios from "axios";
import CryptoJS from "crypto-js"; import CryptoJS from "crypto-js";
@@ -32,31 +32,96 @@ const hashAPIPath = (queryPath) => {
return (queryPath.indexOf("?") > -1 ? "&hash=" : "?hash=") + hashlink; return (queryPath.indexOf("?") > -1 ? "&hash=" : "?hash=") + hashlink;
}; };
export default async function ApiProxy(req, res) { // export default async function ApiProxy(req, res) {
var token = await getToken(); // var token = await getToken();
var data = JSON.stringify(req.body); // var data = JSON.stringify(req.body);
var queryUrl = "pinswg_watchlists"; // var queryUrl = "pinswg_watchlists";
var config = { // console.log(data);
method: "post", // var config = {
// method: "put",
// url: WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
// headers: {
// "OData-MaxVersion": "4.0",
// "OData-Version": "4.0",
// "Accept": "application/json",
// "Prefer": 'odata.include-annotations="*",return=representation',
// "Authorization": "Bearer " + token.access_token,
// "Content-Type": "application/json",
// },
// data: data,
// };
// return axios(config)
// .then(({ data }) => {
// res.status(200).json(data);
// })
// .catch((error) => {
// consoleLogger(Object.assign(err, data));
// res.status(400).json(error);
// });
// }
const recordExists = async (incidentId, contactId, token) => {
const filter = `$filter=pinswg_WatchedCase/incidentid eq ${incidentId} and pinswg_Contact/contactid eq ${contactId}`;
const queryUrl = `pinswg_watchlists?${filter}`;
const url = WEBAPI_URL + queryUrl + hashAPIPath(queryUrl);
try {
const res = await axios.get(url, {
headers: {
Authorization: "Bearer " + token.access_token,
Accept: "application/json",
},
});
if (res.data.value && res.data.value.length > 0) {
return res.data.value[0]; // return the existing record
}
return null;
} catch (err) {
throw err;
}
};
export default async function ApiProxy(req, res) {
const token = await getToken();
const data = req.body;
const incidentId =
data["pinswg_WatchedCase@odata.bind"].match(/\(([^)]+)\)/)[1];
const contactId = data["pinswg_Contact@odata.bind"].match(/\(([^)]+)\)/)[1];
const existingRecord = await recordExists(incidentId, contactId, token);
let method, queryUrl;
if (existingRecord) {
method = "patch";
queryUrl = `pinswg_watchlists(${existingRecord.pinswg_watchlistid})`; // adjust with your primary key logical name
} else {
method = "post";
queryUrl = "pinswg_watchlists";
}
const config = {
method: method,
url: WEBAPI_URL + queryUrl + hashAPIPath(queryUrl), url: WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
headers: { headers: {
"OData-MaxVersion": "4.0", "OData-MaxVersion": "4.0",
"OData-Version": "4.0", "OData-Version": "4.0",
"Accept": "application/json", Accept: "application/json",
"Prefer": 'odata.include-annotations="*",return=representation', Prefer: 'odata.include-annotations="*",return=representation',
"Authorization": "Bearer " + token.access_token, Authorization: "Bearer " + token.access_token,
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
data: data, data: JSON.stringify(data),
}; };
return axios(config) return axios(config)
.then(({ data }) => { .then(({ data }) => res.status(200).json(data))
res.status(200).json(data); .catch((err) => {
}) consoleLogger(err);
.catch((error) => { res.status(400).json(err.response?.data || err);
consoleLogger(Object.assign(err, data));
res.status(400).json(error);
}); });
} }
+27 -1
View File
@@ -43,7 +43,7 @@ export default async function ApiProxy(req, res) {
var queryUrl = var queryUrl =
"pinswg_watchlists?$filter= _pinswg_contact_value eq " + "pinswg_watchlists?$filter= _pinswg_contact_value eq " +
loggedInUserId + loggedInUserId +
"&$select=pinswg_emailnotifications,modifiedon,pinswg_appealcasetype,pinswg_watchlistid,_pinswg_watchedcase_value,statuscode&$count=true&$orderby=createdon desc&$expand=pinswg_WatchedCase($select=pinswg_AssociatedLPA)"; "&$select=pinswg_emailnotifications,modifiedon,pinswg_appealcasetype,pinswg_watchlistid,_pinswg_watchedcase_value,statuscode,pinswg_representationsubmitted,pinswg_representationtype&$count=true&$orderby=createdon desc&$expand=pinswg_WatchedCase($select=pinswg_AssociatedLPA)";
return axios return axios
.get( .get(
@@ -51,6 +51,32 @@ export default async function ApiProxy(req, res) {
azureHeaders(token.access_token) azureHeaders(token.access_token)
) )
.then(({ data }) => { .then(({ data }) => {
data.value.forEach(function (element) {
element.ticketnumber = element.pinswg_WatchedCase?.ticketnumber;
element.pinswg_title =
element[
"_pinswg_watchedcase_value@OData.Community.Display.V1.FormattedValue"
];
element[
"_pinswg_associatedlpa_value@OData.Community.Display.V1.FormattedValue"
] =
element.pinswg_WatchedCase?.[
"_pinswg_associatedlpa_value@OData.Community.Display.V1.FormattedValue"
];
element._pinswg_associatedlpa_value =
element.pinswg_WatchedCase?._pinswg_associatedlpa_value;
element[
"_ownerid_value@OData.Community.Display.V1.FormattedValue"
] =
element.pinswg_WatchedCase?.[
"_ownerid_value@OData.Community.Display.V1.FormattedValue"
];
element._ownerid_value =
element.pinswg_WatchedCase?._ownerid_value;
delete element.pinswg_WatchedCase;
});
res.status(200).json(data); res.status(200).json(data);
}) })
.catch((error) => { .catch((error) => {