Merged PR 1645: 14949 activity from contact us
Related work items: #16290, #16291, #16938
This commit is contained in:
+40
-14
@@ -1896,22 +1896,30 @@ export const sendEmail = async (
|
|||||||
// personalisation,
|
// personalisation,
|
||||||
// reference
|
// reference
|
||||||
// );
|
// );
|
||||||
var queryUrl = "/api/email/notify";
|
// var queryUrl = "/api/email/notify";
|
||||||
|
|
||||||
var config = {
|
// var config = {
|
||||||
method: "post",
|
// method: "post",
|
||||||
url: queryUrl,
|
// url: queryUrl,
|
||||||
data: mailData,
|
// data: mailData,
|
||||||
};
|
// };
|
||||||
|
|
||||||
return axios(config)
|
// return axios(config)
|
||||||
.then((res) => {
|
// .then((res) => {
|
||||||
//console.log("posted ", res.data);
|
// //console.log("posted ", res.data);
|
||||||
return res.data;
|
// return res.data;
|
||||||
})
|
// })
|
||||||
.catch((error) => {
|
// .catch((error) => {
|
||||||
consoleLogger(error);
|
// consoleLogger(error);
|
||||||
});
|
// });
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await axios.post("/api/email/notify", mailData);
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
consoleLogger(error); // Optional custom logging
|
||||||
|
throw error; // ✅ Ensure the calling function sees the error
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getNotice = () => {
|
export const getNotice = () => {
|
||||||
@@ -2117,3 +2125,21 @@ export const getAddressSearch = async (searchString) => {
|
|||||||
return ErrResponse;
|
return ErrResponse;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const createCRMTask = async (formValues) => {
|
||||||
|
var queryUrl = "/api/endpoint/createcrmtask_api";
|
||||||
|
|
||||||
|
var data = formValues;
|
||||||
|
var config = {
|
||||||
|
method: "post",
|
||||||
|
url: queryUrl,
|
||||||
|
data: data,
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await axios(config);
|
||||||
|
return res.data;
|
||||||
|
} catch (error) {
|
||||||
|
consoleLogger(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ const Header = (props) => {
|
|||||||
"/myportal/searchresults",
|
"/myportal/searchresults",
|
||||||
"/myportal/representation",
|
"/myportal/representation",
|
||||||
"/myportal/viewall",
|
"/myportal/viewall",
|
||||||
|
"/contactus",
|
||||||
];
|
];
|
||||||
|
|
||||||
const hasContactLink = [
|
const hasContactLink = [
|
||||||
@@ -280,7 +281,6 @@ const Header = (props) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{" "}
|
{" "}
|
||||||
wwww
|
|
||||||
{t("common:available-in")}
|
{t("common:available-in")}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import useTranslation from "next-translate/useTranslation";
|
import useTranslation from "next-translate/useTranslation";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
import Link from "next/link";
|
||||||
|
|
||||||
export default function CaseComment() {
|
export default function CaseComment() {
|
||||||
let { t } = useTranslation();
|
let { t } = useTranslation();
|
||||||
@@ -24,6 +25,15 @@ export default function CaseComment() {
|
|||||||
<p className="govuk-body-s">
|
<p className="govuk-body-s">
|
||||||
{t("home:casescomment-card-paragraph-two")}
|
{t("home:casescomment-card-paragraph-two")}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<div className="govuk-form-group">
|
||||||
|
<Link
|
||||||
|
href={router.locale == "cy" ? "/cyswllt" : "/contactus"}
|
||||||
|
className="govuk-button withChevron govuk-button-cta"
|
||||||
|
>
|
||||||
|
Contact us
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -171,6 +171,18 @@ let CaseSearch = (props) => {
|
|||||||
>
|
>
|
||||||
{t("myportal:searchcases-card-advanced-link")}
|
{t("myportal:searchcases-card-advanced-link")}
|
||||||
</Link>
|
</Link>
|
||||||
|
<div className="govuk-form-group govuk-!-margin-top-5">
|
||||||
|
<Link
|
||||||
|
href={
|
||||||
|
router.locale == "cy"
|
||||||
|
? "/cyswllt"
|
||||||
|
: "/contactus"
|
||||||
|
}
|
||||||
|
className="govuk-button withChevron govuk-button-cta"
|
||||||
|
>
|
||||||
|
Contact us
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ module.exports = {
|
|||||||
"pages": {
|
"pages": {
|
||||||
"*": ["common", "search"],
|
"*": ["common", "search"],
|
||||||
"/": ["common", "home", "case"],
|
"/": ["common", "home", "case"],
|
||||||
|
"/contactus": ["newappeal", "account"],
|
||||||
"/error": ["common", "home", "myportal"],
|
"/error": ["common", "home", "myportal"],
|
||||||
"/furtherdetails": ["common", "home", "myportal"],
|
"/furtherdetails": ["common", "home", "myportal"],
|
||||||
"/myportal": ["myportal", "common", "home", "case"],
|
"/myportal": ["myportal", "common", "home", "case"],
|
||||||
|
|||||||
@@ -0,0 +1,188 @@
|
|||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /api/endpoint/createcase_api:
|
||||||
|
* post:
|
||||||
|
* tags: [Case]
|
||||||
|
* description: Create case
|
||||||
|
* summary: Phase 2
|
||||||
|
* parameters:
|
||||||
|
* - name: body
|
||||||
|
* in: requestbody
|
||||||
|
* required: true
|
||||||
|
* example: {}
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* - name: contactid
|
||||||
|
* in: query
|
||||||
|
* required: true
|
||||||
|
* example: pinswg_planningappeals78s
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* - name: appealTypeId
|
||||||
|
* in: query
|
||||||
|
* required: true
|
||||||
|
* example: pinswg_planningappeals78id
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* - name: containername
|
||||||
|
* in: query
|
||||||
|
* required: true
|
||||||
|
* example: pinswg_planningappeals78id
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* - name: lpaID
|
||||||
|
* in: query
|
||||||
|
* required: true
|
||||||
|
* example: pinswg_planningappeals78id
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Success
|
||||||
|
*/
|
||||||
|
|
||||||
|
import axios from "axios";
|
||||||
|
import CryptoJS from "crypto-js";
|
||||||
|
import _ from "lodash";
|
||||||
|
import { getToken } from "../../../actions";
|
||||||
|
import { getCaseBlob } from "../../../actions/azurestorage";
|
||||||
|
const WORDKEY = process.env.HASHKEY;
|
||||||
|
|
||||||
|
const WEBAPI_URL =
|
||||||
|
process.env.RELAY_ROOT ||
|
||||||
|
"https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/";
|
||||||
|
|
||||||
|
const hashAPIPath = (queryPath) => {
|
||||||
|
var hashlink = CryptoJS.HmacSHA256(
|
||||||
|
queryPath,
|
||||||
|
CryptoJS.enc.Hex.parse(WORDKEY)
|
||||||
|
);
|
||||||
|
hashlink = hashlink.toString(CryptoJS.enc.Hex);
|
||||||
|
|
||||||
|
//return "&hash=" + hashlink;
|
||||||
|
|
||||||
|
return (queryPath.indexOf("?") > -1 ? "&hash=" : "?hash=") + hashlink;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function ApiProxy(req, res) {
|
||||||
|
var createTaskBody = req.body;
|
||||||
|
var queryUrl = "tasks";
|
||||||
|
var token = await getToken();
|
||||||
|
|
||||||
|
let contactValue = createTaskBody.typeOfContact;
|
||||||
|
|
||||||
|
// const whichTeam = (contactValue) => {
|
||||||
|
// switch (contactValue) {
|
||||||
|
// case "plq":
|
||||||
|
// //Questions about Planning legislation or policy
|
||||||
|
// //PD - Via Email - Planning.Directorate@gov.wales
|
||||||
|
|
||||||
|
// return;
|
||||||
|
// break;
|
||||||
|
// case "ipq":
|
||||||
|
// //Questions or comments about applications for major infrastructure projects
|
||||||
|
// //Infrastructure
|
||||||
|
// return "7fb9e598-7d26-ec11-a97f-00224800e98c";
|
||||||
|
// break;
|
||||||
|
// case "pcpq":
|
||||||
|
// //Questions or comments about planning and environmental appeals
|
||||||
|
// //Casework
|
||||||
|
// return "8ffabad9-7c26-ec11-a97f-00224800e98c";
|
||||||
|
// break;
|
||||||
|
// case "pi":
|
||||||
|
// //Query about using the Casework Portal
|
||||||
|
// // Digital Support Team - PEDW
|
||||||
|
// return "5554882f-4606-ec11-a97f-00224800d374";
|
||||||
|
// break;
|
||||||
|
// case "appadvice":
|
||||||
|
// //Advice How to submit an appeal
|
||||||
|
// //R&D
|
||||||
|
// return "5554882f-4606-ec11-a97f-00224800d374";
|
||||||
|
// break;
|
||||||
|
// case "repadvice":
|
||||||
|
// //Advice How to comment on an appeal or application
|
||||||
|
// //R&D
|
||||||
|
// return "5554882f-4606-ec11-a97f-00224800d374";
|
||||||
|
// break;
|
||||||
|
// case "ceq":
|
||||||
|
// //Queries about forthcoming Hearing or Inquiry event
|
||||||
|
// //Inspector Scheduling
|
||||||
|
// return "4fddd7e8-7d26-ec11-a97f-00224800e98c";
|
||||||
|
// break;
|
||||||
|
// case "other":
|
||||||
|
// //Other enquiry for PEDW
|
||||||
|
// //Casework
|
||||||
|
// return "8ffabad9-7c26-ec11-a97f-00224800e98c";
|
||||||
|
// break;
|
||||||
|
// case "postdec":
|
||||||
|
// //Issues or questions about a case after the decision is issued
|
||||||
|
// //SLT Team
|
||||||
|
// return "cc3d987e-7c26-ec11-a97f-00224800e98c";
|
||||||
|
// break;
|
||||||
|
// case "comp":
|
||||||
|
// //General Complaints of Compliments
|
||||||
|
// //SLT Team
|
||||||
|
// return "cc3d987e-7c26-ec11-a97f-00224800e98c";
|
||||||
|
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// // code block
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// let teamId = whichTeam(contactValue);
|
||||||
|
|
||||||
|
const teamMap = {
|
||||||
|
ipq: "7fb9e598-7d26-ec11-a97f-00224800e98c", // Infrastructure
|
||||||
|
pcpq: "8ffabad9-7c26-ec11-a97f-00224800e98c", // Casework
|
||||||
|
pi: "5554882f-4606-ec11-a97f-00224800d374", // Digital Support Team
|
||||||
|
appadvice: "5554882f-4606-ec11-a97f-00224800d374",
|
||||||
|
repadvice: "5554882f-4606-ec11-a97f-00224800d374",
|
||||||
|
ceq: "4fddd7e8-7d26-ec11-a97f-00224800e98c", // Inspector Scheduling
|
||||||
|
other: "8ffabad9-7c26-ec11-a97f-00224800e98c",
|
||||||
|
postdec: "cc3d987e-7c26-ec11-a97f-00224800e98c", // SLT Team
|
||||||
|
comp: "cc3d987e-7c26-ec11-a97f-00224800e98c",
|
||||||
|
};
|
||||||
|
|
||||||
|
let teamId = teamMap[contactValue];
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
"subject": `Contact Us Enquiry - ${createTaskBody.contactSubject}`,
|
||||||
|
"description": `From: ${createTaskBody.contactEmail}\n\n${createTaskBody.contactbody}`,
|
||||||
|
"scheduledstart": new Date().toISOString(),
|
||||||
|
"scheduledend": new Date(
|
||||||
|
new Date().getTime() + 60 * 60000 * 24
|
||||||
|
).toISOString(), // 30 mins
|
||||||
|
...(teamId && { "ownerid@odata.bind": `/teams(${teamId})` }),
|
||||||
|
};
|
||||||
|
|
||||||
|
//console.log("/////Create Task:\n", payload, "\n//////////////");
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
method: "post",
|
||||||
|
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: JSON.stringify(payload),
|
||||||
|
};
|
||||||
|
|
||||||
|
//console.log("/////Create Task config:\n", config, "\n//////////////");
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { data } = await axios(config);
|
||||||
|
return res.status(200).json(data);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(
|
||||||
|
"CRM Task Creation Error:",
|
||||||
|
error.response?.data || error
|
||||||
|
);
|
||||||
|
return res
|
||||||
|
.status(400)
|
||||||
|
.json({ error: "Failed to create CRM task", details: error });
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,515 @@
|
|||||||
|
import useTranslation from "next-translate/useTranslation";
|
||||||
|
import Head from "next/head";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import Breadcrumbs from "../components/breadcrumbs";
|
||||||
|
import CookieBanner from "../components/cookieBanner";
|
||||||
|
import Footer from "../components/footer";
|
||||||
|
import Header from "../components/header";
|
||||||
|
import ServiceBanner from "../components/servicebanner";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { PickList } from "../components/elements";
|
||||||
|
import {
|
||||||
|
Field,
|
||||||
|
change,
|
||||||
|
formValueSelector,
|
||||||
|
reduxForm,
|
||||||
|
touch,
|
||||||
|
SubmissionError,
|
||||||
|
} from "redux-form";
|
||||||
|
import { connect, submitError } from "react-redux";
|
||||||
|
import { createCRMTask, sendEmail } from "../actions";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
const RenderPickList = ({
|
||||||
|
datafieldname,
|
||||||
|
picklistData,
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
label,
|
||||||
|
input,
|
||||||
|
errorMsg,
|
||||||
|
meta: { touched, error },
|
||||||
|
}) => {
|
||||||
|
let { t } = useTranslation();
|
||||||
|
|
||||||
|
const required = (value) => {
|
||||||
|
return value || value == 0
|
||||||
|
? undefined
|
||||||
|
: t("newappeal:is-required-label");
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
touched && error
|
||||||
|
? "govuk-form-group govuk-!-margin-bottom-1 govuk-form-group--error"
|
||||||
|
: "govuk-form-group govuk-!-margin-bottom-1"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<label className="govuk-label " htmlFor={id} id={id + "_label"}>
|
||||||
|
{label}
|
||||||
|
</label>
|
||||||
|
{touched && error && (
|
||||||
|
<span id={id + "-error"} className="govuk-error-message">
|
||||||
|
<span className="govuk-visually-hidden">Error:</span>{" "}
|
||||||
|
{error}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<select
|
||||||
|
{...input}
|
||||||
|
className="govuk-select govuk-input--width-20"
|
||||||
|
id={id}
|
||||||
|
name={id}
|
||||||
|
>
|
||||||
|
<option value="" disabled defaultValue>
|
||||||
|
{t("newappeal:select-default")}
|
||||||
|
</option>
|
||||||
|
|
||||||
|
<option value="plq">Planning legislation query</option>
|
||||||
|
<option value="ipq">Infrastructure procedure query</option>
|
||||||
|
<option value="pcpq">
|
||||||
|
Planning casework procedure query
|
||||||
|
</option>
|
||||||
|
<option value="pi">Portal Issues</option>
|
||||||
|
<option value="appadvice">Appeal submission advice</option>
|
||||||
|
<option value="repadvice">
|
||||||
|
Representation submission advice
|
||||||
|
</option>
|
||||||
|
<option value="ceq">Casework Events Query</option>
|
||||||
|
<option value="other">Any Other Enquiries</option>
|
||||||
|
<option value="postdec">Post Decision</option>
|
||||||
|
<option value="comp">Complaints/Complements</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const RenderMultiline = ({
|
||||||
|
id,
|
||||||
|
className,
|
||||||
|
rows,
|
||||||
|
cols,
|
||||||
|
datafieldname,
|
||||||
|
name,
|
||||||
|
label,
|
||||||
|
input,
|
||||||
|
errorMsg,
|
||||||
|
meta: { touched, error },
|
||||||
|
...custom
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
touched && error
|
||||||
|
? "govuk-form-group govuk-form-group--error"
|
||||||
|
: "govuk-form-group "
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<label className="govuk-label " htmlFor={id} id={id + "_label"}>
|
||||||
|
{label}
|
||||||
|
</label>
|
||||||
|
{touched && error && (
|
||||||
|
<span id={id + "-error"} className="govuk-error-message">
|
||||||
|
<span className="govuk-visually-hidden">Error:</span>{" "}
|
||||||
|
{errorMsg || error}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<textarea
|
||||||
|
id={id}
|
||||||
|
name={id}
|
||||||
|
rows={rows}
|
||||||
|
cols={cols}
|
||||||
|
className={className}
|
||||||
|
{...input}
|
||||||
|
maxLength={
|
||||||
|
custom.hasOwnProperty("maxFieldLength")
|
||||||
|
? custom.maxFieldLength
|
||||||
|
? custom.maxFieldLength
|
||||||
|
: 800
|
||||||
|
: 800
|
||||||
|
}
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const RenderTextfield = ({
|
||||||
|
id,
|
||||||
|
className,
|
||||||
|
rows,
|
||||||
|
datafieldname,
|
||||||
|
name,
|
||||||
|
label,
|
||||||
|
input,
|
||||||
|
errorMsg,
|
||||||
|
meta: { touched, error },
|
||||||
|
...custom
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
touched && error
|
||||||
|
? "govuk-form-group govuk-form-group--error"
|
||||||
|
: "govuk-form-group "
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<label className="govuk-label " htmlFor={id} id={id + "_label"}>
|
||||||
|
{label}
|
||||||
|
</label>
|
||||||
|
{touched && error && (
|
||||||
|
<span id={id + "-error"} className="govuk-error-message">
|
||||||
|
<span className="govuk-visually-hidden">Error:</span>{" "}
|
||||||
|
{errorMsg || error}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<input
|
||||||
|
{...input}
|
||||||
|
type={"email"}
|
||||||
|
className={className}
|
||||||
|
name={id || name}
|
||||||
|
id={id || name}
|
||||||
|
maxLength={
|
||||||
|
custom.hasOwnProperty("maxFieldLength")
|
||||||
|
? custom.maxFieldLength
|
||||||
|
? custom.maxFieldLength
|
||||||
|
: 100
|
||||||
|
: 200
|
||||||
|
}
|
||||||
|
pattern={
|
||||||
|
custom.hasOwnProperty("pattern")
|
||||||
|
? custom.pattern
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const contactPurpose = (contactValue) => {
|
||||||
|
let contactPurposeBody;
|
||||||
|
|
||||||
|
switch (contactValue) {
|
||||||
|
case "plq":
|
||||||
|
contactPurposeBody = (
|
||||||
|
<p className="govuk-body">
|
||||||
|
Questions about Planning legislation or policy
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "ipq":
|
||||||
|
contactPurposeBody = (
|
||||||
|
<p className="govuk-body">
|
||||||
|
Questions or comments about applications for major
|
||||||
|
infrastructure projects
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "pcpq":
|
||||||
|
contactPurposeBody = (
|
||||||
|
<p className="govuk-body">
|
||||||
|
Questions or comments about planning and environmental
|
||||||
|
appeals
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "pi":
|
||||||
|
contactPurposeBody = (
|
||||||
|
<p className="govuk-body">
|
||||||
|
Query about using the Casework Portal
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "appadvice":
|
||||||
|
contactPurposeBody = (
|
||||||
|
<p className="govuk-body">Advice How to submit an appeal</p>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "repadvice":
|
||||||
|
contactPurposeBody = (
|
||||||
|
<p className="govuk-body">
|
||||||
|
Advice How to comment on an appeal or application
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "ceq":
|
||||||
|
contactPurposeBody = (
|
||||||
|
<p className="govuk-body">
|
||||||
|
Queries about forthcoming Hearing or Inquiry event
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "other":
|
||||||
|
contactPurposeBody = (
|
||||||
|
<p className="govuk-body">Other enquiry for PEDW</p>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "postdec":
|
||||||
|
contactPurposeBody = (
|
||||||
|
<p className="govuk-body">
|
||||||
|
Issues or questions about a case after the decision is
|
||||||
|
issued
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case "comp":
|
||||||
|
contactPurposeBody = (
|
||||||
|
<p className="govuk-body">General Complaints of Compliments</p>
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// code block
|
||||||
|
}
|
||||||
|
|
||||||
|
return contactPurposeBody;
|
||||||
|
};
|
||||||
|
|
||||||
|
let t;
|
||||||
|
|
||||||
|
let ContactUs = (props) => {
|
||||||
|
const { footerLinks, pages } = props;
|
||||||
|
let { t } = useTranslation();
|
||||||
|
|
||||||
|
const [formSubmitted, setFormSubmitted] = useState(false);
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const { locale } = router;
|
||||||
|
|
||||||
|
const required = (value) =>
|
||||||
|
value ? undefined : t("newappeal:is-required-label");
|
||||||
|
|
||||||
|
const emailRegex =
|
||||||
|
/^(?:[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}|(?:\[(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-zA-Z0-9-]*[a-zA-Z0-9]:.+)])$/;
|
||||||
|
|
||||||
|
const email = (value) =>
|
||||||
|
value && !emailRegex.test(value)
|
||||||
|
? t("account:invalid-email-address-errormsg")
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const onSubmit = async (formValues) => {
|
||||||
|
// Only called if validation passes
|
||||||
|
sendContactEmail(formValues);
|
||||||
|
createCRMTask(formValues);
|
||||||
|
console.log("Form submitted:", formValues);
|
||||||
|
};
|
||||||
|
|
||||||
|
const sendContactEmail = async (formValues) => {
|
||||||
|
Object.assign(formValues, {
|
||||||
|
"contactSubject": contactPurpose(formValues.typeOfContact).props
|
||||||
|
.children,
|
||||||
|
});
|
||||||
|
|
||||||
|
const reference = "PEDW-CONTACT-US";
|
||||||
|
const templateId = "69228c5f-8500-40ff-a6c5-95a9434c3ec8";
|
||||||
|
const templateIdCY = "b8f1f76d-4ab9-4a2f-b294-e3623c6095a3";
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await sendEmail(
|
||||||
|
router.locale !== "en" ? templateIdCY : templateId,
|
||||||
|
formValues.contactEmail,
|
||||||
|
formValues,
|
||||||
|
reference
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log("Email sent successfully.");
|
||||||
|
setFormSubmitted(true);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Email sending failed:", error);
|
||||||
|
alert("Something went wrong. Please try again later.");
|
||||||
|
// Required: inform redux-form this is a submit error
|
||||||
|
throw new SubmissionError({
|
||||||
|
_error: "Failed to send email. Please try again later.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Head>
|
||||||
|
<title>{t("common:service-name")}</title>
|
||||||
|
</Head>
|
||||||
|
<div id="page_wrapper">
|
||||||
|
<CookieBanner />
|
||||||
|
<Header />
|
||||||
|
<div className="govuk-width-container">
|
||||||
|
<Breadcrumbs />
|
||||||
|
<ServiceBanner />
|
||||||
|
<main
|
||||||
|
className="govuk-main-wrapper govuk-!-padding-top-9 govuk-main-wrapper--auto-spacing"
|
||||||
|
id="main-content"
|
||||||
|
role="main"
|
||||||
|
>
|
||||||
|
<div className="govuk-grid-row">
|
||||||
|
<div className="govuk-grid-column-full">
|
||||||
|
<h2 className="govuk-heading-l govuk-!-margin-bottom-7">
|
||||||
|
Contact us{" "}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div className="wgForm">
|
||||||
|
{formSubmitted ? (
|
||||||
|
<div className="govuk-panel govuk-panel--confirmation">
|
||||||
|
<h1 className="govuk-panel__title">
|
||||||
|
Thank you for your enquiry
|
||||||
|
</h1>
|
||||||
|
<div className="govuk-panel__body">
|
||||||
|
We’ll get back to you as soon as
|
||||||
|
we can.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<p className="govuk-body">
|
||||||
|
Lorem ipsum dolor sit amet,
|
||||||
|
consectetur adipiscing elit.
|
||||||
|
Nulla congue leo ac quam
|
||||||
|
pulvinar, id vulputate libero
|
||||||
|
volutpat. Maecenas ut odio id
|
||||||
|
nisl laoreet dictum. Nam
|
||||||
|
faucibus, leo vitae egestas
|
||||||
|
lacinia, enim tortor bibendum
|
||||||
|
lorem, ut tincidunt lacus sapien
|
||||||
|
quis lorem. Aenean interdum
|
||||||
|
dolor augue, ac cursus lectus
|
||||||
|
suscipit vitae.{" "}
|
||||||
|
</p>
|
||||||
|
<form
|
||||||
|
onSubmit={props.handleSubmit(
|
||||||
|
onSubmit
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Field
|
||||||
|
name={"contactEmail"}
|
||||||
|
id={"contactEmail"}
|
||||||
|
label="Your email address"
|
||||||
|
component={RenderTextfield}
|
||||||
|
validate={[required, email]}
|
||||||
|
className="govuk-input govuk-input--width-20"
|
||||||
|
type="email"
|
||||||
|
/>
|
||||||
|
<Field
|
||||||
|
name="typeOfContact"
|
||||||
|
id="typeOfContact"
|
||||||
|
component={RenderPickList}
|
||||||
|
label="What do you want to contact us about?"
|
||||||
|
validate={[required]}
|
||||||
|
/>
|
||||||
|
<div className="govuk-form-group">
|
||||||
|
{props.typeOfContactValue && (
|
||||||
|
<div>
|
||||||
|
{contactPurpose(
|
||||||
|
props.typeOfContactValue
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<Field
|
||||||
|
name="contactbody"
|
||||||
|
id="contactbody"
|
||||||
|
component={RenderMultiline}
|
||||||
|
label="What do you want to ask?"
|
||||||
|
rows={10}
|
||||||
|
cols={80}
|
||||||
|
validate={[required]}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="govuk-button"
|
||||||
|
>
|
||||||
|
Send your question
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="govuk-button govuk-button--secondary govuk-!-margin-left-5"
|
||||||
|
onClick={props.reset}
|
||||||
|
>
|
||||||
|
Clear form
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Footer footerLinks={footerLinks} ticketnumber={props} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const selector = formValueSelector("contactUsForm"); // <-- same as form name
|
||||||
|
|
||||||
|
// ContactUs = connect((state) => {
|
||||||
|
// const typeOfContactValue = selector(state, "typeOfContact");
|
||||||
|
|
||||||
|
// return {
|
||||||
|
// typeOfContactValue,
|
||||||
|
// initialValues: {
|
||||||
|
// contactEmail:
|
||||||
|
// state.accountDetails.accountDetails?.emailaddress1 || "",
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
// })(ContactUs);
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => ({});
|
||||||
|
|
||||||
|
const mapStateToProps = (state) => {
|
||||||
|
const typeOfContactValue = selector(state, "typeOfContact");
|
||||||
|
const email = state.accountDetails.accountDetails?.emailaddress1;
|
||||||
|
|
||||||
|
return {
|
||||||
|
typeOfContactValue,
|
||||||
|
initialValues: email ? { contactEmail: email } : {},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(
|
||||||
|
reduxForm({
|
||||||
|
form: "contactUsForm",
|
||||||
|
enableReinitialize: true,
|
||||||
|
destroyOnUnmount: false,
|
||||||
|
touchOnBlur: true,
|
||||||
|
touchOnChange: true,
|
||||||
|
onSubmitFail: (errors, dispatch, subnittError, props) => {
|
||||||
|
if (errors) {
|
||||||
|
// Touch all fields with errors so validation messages appear
|
||||||
|
const errorFields = Object.keys(errors);
|
||||||
|
dispatch(touch("contactUsForm", ...errorFields));
|
||||||
|
|
||||||
|
// Scroll to first error
|
||||||
|
const firstErrorField = errorFields[0];
|
||||||
|
const errorElement = document.querySelector(
|
||||||
|
`[name="${firstErrorField}"]`
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
errorElement &&
|
||||||
|
typeof errorElement.scrollIntoView === "function"
|
||||||
|
) {
|
||||||
|
errorElement.scrollIntoView({
|
||||||
|
behavior: "smooth",
|
||||||
|
block: "center",
|
||||||
|
});
|
||||||
|
errorElement.focus({ preventScroll: true });
|
||||||
|
} else {
|
||||||
|
console.warn(
|
||||||
|
"Could not find element for error field:",
|
||||||
|
firstErrorField
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Redux Form onSubmitFail:", submitError);
|
||||||
|
},
|
||||||
|
})(ContactUs)
|
||||||
|
);
|
||||||
Reference in New Issue
Block a user