From be476394c8be2ce50277ac2b494857474b500462 Mon Sep 17 00:00:00 2001 From: rdbsolutions Date: Fri, 23 Jul 2021 14:32:57 +0100 Subject: [PATCH] added validation methods --- .gitignore | 20 +- components/breadcrumbs.js | 16 ++ components/elements/index.js | 303 +++++++++++++++------- components/header.js | 19 +- components/homepage/casesearch.js | 48 +++- components/myportal/searchcases.js | 40 ++- components/newappeal/buildcheckrow.js | 2 - components/newappeal/buildchecksection.js | 1 + components/newappeal/buildfield.js | 6 +- components/newappeal/buildrow.js | 40 ++- components/newappeal/buildsection.js | 83 +++++- components/newappeal/createCase.js | 246 +++++++++++------- pages/newappeal/[appealtypes].js | 71 ++--- pages/newappeal/index.js | 30 ++- pages/newappeal/selectappeal.js | 72 ++--- 15 files changed, 668 insertions(+), 329 deletions(-) diff --git a/.gitignore b/.gitignore index 34c59104..f67b7a05 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,19 @@ -node_modules +// .gitignore +# next.js build output .next -package-lock.json + +# dotenv environment variables file - set in pipeline as environment variables +.env +.env.build + +# Dependency directories +node_modules/ + +# Logs +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +#lock files +yarn.lock +package-lock.json \ No newline at end of file diff --git a/components/breadcrumbs.js b/components/breadcrumbs.js index fe66a013..aa86ae8b 100644 --- a/components/breadcrumbs.js +++ b/components/breadcrumbs.js @@ -72,6 +72,22 @@ const Breadcrumbs = (props) => { ) : ( "" )} + {router.pathname == "/searchresults" ? ( + <> +
  • + + + My Portal + + +
  • +
  • + Search results +
  • + + ) : ( + "" + )} {router.pathname == "/newappeal" ? ( <>
  • diff --git a/components/elements/index.js b/components/elements/index.js index cba0c911..7f8d1e2c 100644 --- a/components/elements/index.js +++ b/components/elements/index.js @@ -6,25 +6,77 @@ import React, { useState } from "react"; import "react-datepicker/dist/react-datepicker.css"; import moment from "moment"; +const RenderTextfield = ({ + id, + className, + rows, + datafieldname, + name, + label, + input, + errorMsg, + meta: { touched, error }, + ...custom +}) => { + return ( + <> +
    + + {touched && error && ( + + Error:{" "} + {errorMsg} + + )} + +
    + + ); +}; + export function Textfield(props) { const { name, label } = props; + const required = (value) => (value ? undefined : "Required"); return ( -
    - - -
    + ); } +const RenderMultiline = ({ + className, + rows, + datafieldname, + name, + label, + input, + meta: { touched, error }, + ...custom +}) => { + return ( + <> + + + ); +}; + export function MultiLinefield(props) { const { name, label } = props; @@ -42,13 +94,14 @@ export function MultiLinefield(props) { Do not include personal or financial information, like your National Insurance number or credit card details. + @@ -59,48 +112,73 @@ const RenderDatePicker = ({ datafieldname, name, label, + id, + errorMsg, input: { onChange, value }, meta: { touched, error }, ...custom }) => { return ( <> - +
    + + + + {touched && error && ( + + + Error: + {" "} + {errorMsg} + + )} + - - {touched && error && {error}} + // value={!value ? null : new Date(value)} + /> +
    + ); }; export function DateFieldPicker(props) { const { name, label } = props; + const required = (value) => (value ? undefined : "Required"); + return ( -
    -
    - - - - -
    -
    + ); } @@ -183,47 +261,96 @@ export function DateField(props) { ); } +const RenderYesNo = ({ + datafieldname, + name, + label, + id, + errorMsg, + options, + input: { onChange, value }, + meta: { touched, error }, + ...custom +}) => { + return ( + <> +
    +
    + + + + {touched && error && ( + + + Error: + {" "} + {errorMsg} + + )} +
    + {Object.keys(options).map((key, index) => ( +
    + + +
    + ))} +
    +
    +
    + + ); +}; + export function YesNofield(props) { const { name, label } = props; const yesNo = ["Yes", "No"]; - return ( -
    -
    - - - + const required = (value) => (value ? undefined : "Required"); -
    - {Object.keys(yesNo).map((key, index) => ( -
    - - -
    - ))} -
    -
    -
    + return ( + ); } @@ -232,18 +359,15 @@ const RenderPickList = ({ name, label, input, - meta: { touched, error }, + meta: { touched, errorStr }, }) => { const fetcher = (url) => fetch(url).then((res) => res.json()); - const { data, errorStr } = useSWR("/api/lookups/" + datafieldname, fetcher); - if (errorStr) + const { data, error } = useSWR("/api/lookups/" + datafieldname, fetcher); + if (error) return (
    -
    ); }; @@ -351,7 +476,7 @@ const RenderCaseID = {}; export function ReadOnlyfield(props) { const { name, label, value } = props; - console.log(props.value.refno); + //console.log(props.value.refno); return (
    {router.path} diff --git a/components/homepage/casesearch.js b/components/homepage/casesearch.js index c4161b39..720918f8 100644 --- a/components/homepage/casesearch.js +++ b/components/homepage/casesearch.js @@ -9,17 +9,24 @@ export default function CaseSearch() { const router = useRouter(); const { locale } = router; const [query, setQuery] = useState(""); + const [validationError, setValidationError] = useState(""); const handleParam = (setValue) => (e) => setValue(e.target.value); const basicSearch = (event) => { event.preventDefault(); - console.log(query); - // /searchresults - router.push({ - pathname: "/searchresults", - query: { q: query }, - }); + if (query == "" || query == null) { + setValidationError(true); + } else { + setValidationError(false); + console.log(query); + // /searchresults + + router.push({ + pathname: "/searchresults", + query: { q: query }, + }); + } }; return ( @@ -29,8 +36,14 @@ export default function CaseSearch() {

    {t("home:casesearch-card-title")}

    -
    -
    +
    +
    {t("home:casesearch-card-search-hint")}:
    @@ -41,15 +54,26 @@ export default function CaseSearch() { )} : {" "} - APP/A1234/A/99/1234567 + CAS-00009-W8N6W4
    + {validationError && ( + + + Error: + {" "} + Case reference is required + + )}
    diff --git a/components/myportal/searchcases.js b/components/myportal/searchcases.js index df743b8c..955dbafe 100644 --- a/components/myportal/searchcases.js +++ b/components/myportal/searchcases.js @@ -9,17 +9,24 @@ export default function SearchCases() { const router = useRouter(); const { locale } = router; const [query, setQuery] = useState(""); + const [validationError, setValidationError] = useState(""); const handleParam = (setValue) => (e) => setValue(e.target.value); const basicSearch = (event) => { event.preventDefault(); - console.log(query); - // /searchresults - router.push({ - pathname: "/searchresults", - query: { q: query }, - }); + if (query == "" || query == null) { + setValidationError(true); + } else { + setValidationError(false); + console.log(query); + // /searchresults + + router.push({ + pathname: "/searchresults", + query: { q: query }, + }); + } }; return ( @@ -29,7 +36,13 @@ export default function SearchCases() {

    {t("myportal:searchcases-card-title")}

    -
    +
    {t("myportal:searchcases-card-search-hint")}:
    @@ -41,9 +54,20 @@ export default function SearchCases() { )} : {" "} - APP/A1234/A/99/1234567 + CAS-00009-W8N6W4
    + {validationError && ( + + + Error: + {" "} + Case reference is required + + )} { var fieldtype = xpath.select("//@classid", doc); var datafieldname = xpath.select("//@datafieldname", doc); - console.log(props.form); - return (
    diff --git a/components/newappeal/buildchecksection.js b/components/newappeal/buildchecksection.js index 4efc1457..ca02941a 100644 --- a/components/newappeal/buildchecksection.js +++ b/components/newappeal/buildchecksection.js @@ -73,6 +73,7 @@ let BuildCheckSection = (props) => { whichSection={parseInt(key) + 1} sectionCount={key} props={props} + key={key} /> diff --git a/components/newappeal/buildfield.js b/components/newappeal/buildfield.js index f8f0f860..520749ee 100644 --- a/components/newappeal/buildfield.js +++ b/components/newappeal/buildfield.js @@ -97,10 +97,6 @@ export default function BuildField(props) { }; return ( -
    -
    - {whichFieldType(props.fieldType)} -
    -
    +
    {whichFieldType(props.fieldType)}
    ); } diff --git a/components/newappeal/buildrow.js b/components/newappeal/buildrow.js index 5f29f2de..f5211c4e 100644 --- a/components/newappeal/buildrow.js +++ b/components/newappeal/buildrow.js @@ -15,27 +15,25 @@ export default function BuildRow(props) { const parser = new DOMParser(); return ( -
    -
    - {Object.keys(rowXML).map((key, index) => { - var doc = parser.parseFromString( - rowXML[key].outerHTML, - "text/xml" - ); - var rows = xpath.select("//label/@description", doc); - var fieldtype = xpath.select("//@classid", doc); - var datafieldname = xpath.select("//@datafieldname", doc); - return ( - - ); - })} -
    +
    + {Object.keys(rowXML).map((key, index) => { + var doc = parser.parseFromString( + rowXML[key].outerHTML, + "text/xml" + ); + var rows = xpath.select("//label/@description", doc); + var fieldtype = xpath.select("//@classid", doc); + var datafieldname = xpath.select("//@datafieldname", doc); + return ( + + ); + })}
    ); } diff --git a/components/newappeal/buildsection.js b/components/newappeal/buildsection.js index 5d7f4e12..0002d5dd 100644 --- a/components/newappeal/buildsection.js +++ b/components/newappeal/buildsection.js @@ -1,10 +1,11 @@ import Link from "next/link"; +import _, { has } from "lodash"; import { useRouter } from "next/router"; import useTranslation from "next-translate/useTranslation"; import { useState, useEffect } from "react"; import xpath from "xpath"; import BuildRow from "./buildrow"; -import { reduxForm, formValueSelector } from "redux-form"; +import { reduxForm, formValueSelector, getFormSubmitErrors } from "redux-form"; import { useDispatch, useSelector, shallowEqual, connect } from "react-redux"; import { setCaseReference, @@ -56,12 +57,73 @@ let BuildSection = (props) => { const onHandleSubmit = (values) => { setCurrentSection(currentSection + 1); - setCaseReference(router.query.refno); }; - // const initialValues = { - // email: router.query.refno, - // }; + const [hasErrors, setHasErrors] = useState(""); + + const getErrors = () => { + let errorsobj = props.props.form["appealForm"]; + setHasErrors(errorsobj.hasOwnProperty("syncErrors")); + window.scrollTo(0, 0); + }; + + let errorsobj = {}; + const ShowErrorHeader = (props) => { + errorsobj = props.props.appealForm.syncErrors; + errorsobj = _.keys(errorsobj); + + const getErrorLabel = (whichField) => { + var doc = parser.parseFromString(props.formXML, "text/xml"); + var errorFieldLabel = xpath.select( + "//*[control/@id='" + whichField + "']//@description", + doc + ); + + return errorFieldLabel[0].value; + }; + + const ShowErrors = () => { + let errorList = []; + for (let i = 0; i < errorsobj.length; ++i) { + //get label from error key - search rowxml for id = errorobj + + errorList.push( +
  • + + {" "} + {getErrorLabel(errorsobj[i])} + +
  • + ); + } + + return errorList; + }; + + return !_.isEmpty(errorsobj) ? ( +
    +

    + The following fields have a problem : +

    +
    +
      + +
    +
    +
    + ) : ( + "" + ); + }; return (
    @@ -70,6 +132,16 @@ let BuildSection = (props) => { {titles[0].value}{" "}
    + {hasErrors == true ? ( + + ) : ( + "" + )} + { type="submit" className="govuk-button" data-module="govuk-button" + onClick={() => getErrors()} > Continue diff --git a/components/newappeal/createCase.js b/components/newappeal/createCase.js index 2c004a81..f80c367e 100644 --- a/components/newappeal/createCase.js +++ b/components/newappeal/createCase.js @@ -15,8 +15,6 @@ import { getAppealTypeObj, } from "../../store/appealType/action"; -import { createCase } from "../../actions"; - let CreateCase = (props) => { // useEffect(() => { // window.scrollTo(0, 0); @@ -29,37 +27,85 @@ let CreateCase = (props) => { const { LPAData, onSubmit, handleSubmit } = props; - const appealOptionsObj = props.appealType.appealTypeOptions.GlobalOptionSet - .Options || [{}]; + const appealOptionsObj = _.isEmpty(props) + ? [{}] + : _.isEmpty(props.appealType) + ? [{}] + : _.isEmpty(props.appealType.appealTypeOptions) + ? [{}] + : _.isEmpty(props.appealType.appealTypeOptions.GlobalOptionSet) + ? [{}] + : _.isEmpty(props.appealType.appealTypeOptions.GlobalOptionSet.Options) + ? [{}] + : props.appealType.appealTypeOptions.GlobalOptionSet.Options; - let lpaOptionsObj = jsonpath.query(props.LPAData.LPAData, "$..name"); + let lpaOptionsObj = _.isEmpty(props) + ? [{}] + : _.isEmpty(props.LPAData) + ? [{}] + : _.isEmpty(props.LPAData.LPAData) + ? [{}] + : jsonpath.query(props.LPAData.LPAData, "$..name"); const RenderLPAList = ({ name, input, optionsObj, meta: { touched, error }, + label, + errorMsg, }) => { return ( -
    - props.onChangeSelectLPA(e)} + > + - ); - })} - - {touched && error && {error}} -
    + {_.isEmpty(optionsObj) + ? "" + : Object.keys(optionsObj).map((key, index) => { + return ( + + ); + })} + +
    +
    + ); }; @@ -68,97 +114,99 @@ let CreateCase = (props) => { input, optionsObj, meta: { touched, error }, + label, + errorMsg, }) => { return ( -
    - props.onChangeSelectAppealType(e)} + > + - ); - })} - - {touched && error && {error}} -
    + {_.isEmpty(optionsObj) + ? "" + : Object.keys(optionsObj).map((key, index) => { + return ( + + ); + })} + +
    +
    + ); }; + const required = (value) => (value ? undefined : "Required"); + const onHandleSubmit = (values) => { event.preventDefault(); - - console.log(createCase("asasa", "asasa")); - - const caseReference = createCase("123123", "213132"); - - router.replace( - "/newappeal/" + values.appealTypes + "?refno=" + caseReference, - null, - { - shallow: true, - } - ); - console.log(values); + router.replace("/newappeal/" + values.appealTypes, null, { + shallow: true, + }); }; return ( -
    - - - {/* */} -
    + + + -
    - - - {/* */} -
    @@ -144,14 +152,17 @@ let Home = (props) => { export const getServerSideProps = wrapper.getServerSideProps( (store) => async ({ query, req, res }) => { - console.log("the query", query); + //console.log("the query", query); store.dispatch(setAppealTypeID(query.appealtypes)); const appealTypeData = await getAppealsTypes(); const formdata = (await getFormData(query.appealtypes)) || null; + const caseReference = createCase("asasa", "asasa"); + let xmlStr = formdata; xmlStr = formdata.value[0].formxml; xmlStr = xmlStr.replace(/\\"/g, ""); + store.dispatch(setCaseReference(caseReference)); store.dispatch(setForm(xmlStr)); store.dispatch(setAppealType(appealTypeData)); } diff --git a/pages/newappeal/index.js b/pages/newappeal/index.js index c39cf5be..2c517816 100644 --- a/pages/newappeal/index.js +++ b/pages/newappeal/index.js @@ -49,22 +49,26 @@ const Home = (props) => {
    +
    +
    +
    +
    + + -
    -
    -
    - - - -

    New Appeal

    - +

    New Appeal

    + +
    -
    - +
    diff --git a/pages/newappeal/selectappeal.js b/pages/newappeal/selectappeal.js index 1a77503d..3f6c4590 100644 --- a/pages/newappeal/selectappeal.js +++ b/pages/newappeal/selectappeal.js @@ -68,45 +68,49 @@ const Home = (props) => {
    +
    +
    +
    +
    + + -
    -
    -
    - - +

    New Appeal

    -

    New Appeal

    - - -
    -
    - - + Continue + + +
    -
    - +