diff --git a/components/header.js b/components/header.js
index f00769e1..cab4ce5b 100644
--- a/components/header.js
+++ b/components/header.js
@@ -60,6 +60,7 @@ const Header = (props) => {
"/myportal/searchresults",
"/myportal/representation",
"/myportal/viewall",
+ "/contactus",
];
const hasContactLink = [
@@ -280,7 +281,6 @@ const Header = (props) => {
}}
>
{" "}
- wwww
{t("common:available-in")}
diff --git a/components/homepage/casecomment.js b/components/homepage/casecomment.js
index 57235c3b..c84915a1 100644
--- a/components/homepage/casecomment.js
+++ b/components/homepage/casecomment.js
@@ -1,5 +1,6 @@
import useTranslation from "next-translate/useTranslation";
import { useRouter } from "next/router";
+import Link from "next/link";
export default function CaseComment() {
let { t } = useTranslation();
@@ -24,6 +25,15 @@ export default function CaseComment() {
{t("home:casescomment-card-paragraph-two")}
+
+
+
+ Contact us
+
+
);
diff --git a/components/myportal/searchcases.js b/components/myportal/searchcases.js
index f7167d30..da79bd11 100644
--- a/components/myportal/searchcases.js
+++ b/components/myportal/searchcases.js
@@ -171,6 +171,18 @@ let CaseSearch = (props) => {
>
{t("myportal:searchcases-card-advanced-link")}
+
+
+ Contact us
+
+
diff --git a/i18n.js b/i18n.js
index bfe06a35..725893d7 100644
--- a/i18n.js
+++ b/i18n.js
@@ -11,6 +11,7 @@ module.exports = {
"pages": {
"*": ["common", "search"],
"/": ["common", "home", "case"],
+ "/contactus": ["newappeal", "account"],
"/error": ["common", "home", "myportal"],
"/furtherdetails": ["common", "home", "myportal"],
"/myportal": ["myportal", "common", "home", "case"],
diff --git a/pages/contactus.js b/pages/contactus.js
new file mode 100644
index 00000000..5e4ccc35
--- /dev/null
+++ b/pages/contactus.js
@@ -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 (
+ <>
+
+
+ {label}
+
+ {touched && error && (
+
+ Error: {" "}
+ {error}
+
+ )}
+
+
+ {t("newappeal:select-default")}
+
+
+ Planning legislation query
+ Infrastructure procedure query
+
+ Planning casework procedure query
+
+ Portal Issues
+ Appeal submission advice
+
+ Representation submission advice
+
+ Casework Events Query
+ Any Other Enquiries
+ Post Decision
+ Complaints/Complements
+
+
+ >
+ );
+};
+
+const RenderMultiline = ({
+ id,
+ className,
+ rows,
+ cols,
+ datafieldname,
+ name,
+ label,
+ input,
+ errorMsg,
+ meta: { touched, error },
+ ...custom
+}) => {
+ return (
+ <>
+
+
+ {label}
+
+ {touched && error && (
+
+ Error: {" "}
+ {errorMsg || error}
+
+ )}
+
+
+ >
+ );
+};
+
+const RenderTextfield = ({
+ id,
+ className,
+ rows,
+ datafieldname,
+ name,
+ label,
+ input,
+ errorMsg,
+ meta: { touched, error },
+ ...custom
+}) => {
+ return (
+ <>
+
+
+ {label}
+
+ {touched && error && (
+
+ Error: {" "}
+ {errorMsg || error}
+
+ )}
+
+
+ >
+ );
+};
+
+const contactPurpose = (contactValue) => {
+ let contactPurposeBody;
+
+ switch (contactValue) {
+ case "plq":
+ contactPurposeBody = (
+
+ Questions about Planning legislation or policy
+
+ );
+ break;
+ case "ipq":
+ contactPurposeBody = (
+
+ Questions or comments about applications for major
+ infrastructure projects
+
+ );
+ break;
+ case "pcpq":
+ contactPurposeBody = (
+
+ Questions or comments about planning and environmental
+ appeals
+
+ );
+ break;
+ case "pi":
+ contactPurposeBody = (
+
+ Query about using the Casework Portal
+
+ );
+ break;
+ case "appadvice":
+ contactPurposeBody = (
+ Advice How to submit an appeal
+ );
+ break;
+ case "repadvice":
+ contactPurposeBody = (
+
+ Advice How to comment on an appeal or application
+
+ );
+ break;
+ case "ceq":
+ contactPurposeBody = (
+
+ Queries about forthcoming Hearing or Inquiry event
+
+ );
+ break;
+ case "other":
+ contactPurposeBody = (
+ Other enquiry for PEDW
+ );
+ break;
+ case "postdec":
+ contactPurposeBody = (
+
+ Issues or questions about a case after the decision is
+ issued
+
+ );
+ break;
+ case "comp":
+ contactPurposeBody = (
+ General Complaints of Compliments
+ );
+ 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 (
+
+
+
{t("common:service-name")}
+
+
+
+
+
+
+
+
+
+
+
+ Contact us{" "}
+
+
+
+ {formSubmitted ? (
+
+
+ Thank you for your enquiry
+
+
+ We’ll get back to you as soon as
+ we can.
+
+
+ ) : (
+ <>
+
+ 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.{" "}
+
+
+ >
+ )}
+
+
+
+
+
+
+
+
+
+ );
+};
+
+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)
+);