added check answer summary & complete appeal step

This commit is contained in:
2021-07-16 10:02:25 +01:00
parent 4b81d694da
commit 7711d32ab8
13 changed files with 479 additions and 68 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ import https from "https";
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0; process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
let BASE_URL; let BASE_URL;
BASE_URL = process.env.API_ROOT || "http://localhost:3000"; BASE_URL = process.env.API_ROOT || "http://localhost";
const agent = new https.Agent({ const agent = new https.Agent({
rejectUnauthorized: false, rejectUnauthorized: false,
+33
View File
@@ -0,0 +1,33 @@
import Link from "next/link";
import { useRouter } from "next/router";
import { useContext } from "react";
import useTranslation from "next-translate/useTranslation";
import BuildCheckSection from "./newappeal/buildchecksection";
const CheckAnswers = (props) => {
const { formXML, formTitle, rowXML, whichSection, sectionCount, onSubmit } =
props;
let { t } = useTranslation();
const router = useRouter();
const { locale } = router;
return (
<main
className="govuk-main-wrapper govuk-main-wrapper--auto-spacing"
id="main-content"
role="main"
>
sss
<BuildCheckSection
formXML={formXML}
sectionCount={sectionCount}
onSubmit={onSubmit}
formTitle={formTitle}
/>
</main>
);
};
export default CheckAnswers;
+35 -20
View File
@@ -173,23 +173,23 @@ export function YesNofield(props) {
); );
} }
export function PickList(props) { const RenderPickList = ({
const { name, label, datafieldname } = props; datafieldname,
name,
label,
input,
meta: { touched, error },
}) => {
const fetcher = (url) => fetch(url).then((res) => res.json()); const fetcher = (url) => fetch(url).then((res) => res.json());
const { data, error } = useSWR("/api/lookups/" + datafieldname, fetcher); const { data, errorStr } = useSWR("/api/lookups/" + datafieldname, fetcher);
if (error) if (errorStr)
return ( return (
<div className="govuk-form-group"> <div className="govuk-form-group">
<label className="govuk-label govuk-body-m" htmlFor="sort"> <label className="govuk-label govuk-body-m" htmlFor="sort">
{props.label} {label}
</label> </label>
<select <select className="govuk-select" id={name} name={name}>
className="govuk-select"
id={props.name}
name={props.name}
>
<option value="">empty</option> <option value="">empty</option>
</select> </select>
</div> </div>
@@ -197,33 +197,48 @@ export function PickList(props) {
if (!data) if (!data)
return ( return (
<div> <div>
<div className="govuk-form-group">{props.label} loading...</div> <div className="govuk-form-group">{label} loading...</div>
</div> </div>
); );
console.log(JSON.stringify(data.GlobalOptionSet.Options)); console.log(JSON.stringify(data.GlobalOptionSet.Options));
const dropdownObj = data.GlobalOptionSet.Options; const dropdownObj = data.GlobalOptionSet.Options;
return ( return (
<div className="govuk-form-group"> <div>
<label className="govuk-label govuk-body-m" htmlFor="sort"> <select {...input} className="govuk-select" id={name} name={name}>
{props.label}
</label>
<select className="govuk-select" id={props.name} name={props.name}>
{Object.keys(dropdownObj).map((key, index) => { {Object.keys(dropdownObj).map((key, index) => {
return ( return (
<option <option
key={key} key={key}
value={ value={
dropdownObj[key].Label.LocalizedLabels[0] dropdownObj[key].Label.LocalizedLabels[0].value
.MetadataId
} }
// value={dropdownObj[key].Label.LocalizedLabels[0].MetadataId}
> >
{dropdownObj[key].Label.LocalizedLabels[0].Label} {dropdownObj[key].Label.LocalizedLabels[0].Label}
</option> </option>
); );
})} })}
</select> </select>
{touched && error && <span>{error}</span>}
</div>
);
};
export function PickList(props) {
const { name, label, datafieldname } = props;
return (
<div className="govuk-form-group">
<label className="govuk-label govuk-body-m" htmlFor="sort">
{props.label}
</label>
<Field
name={props.name}
component={RenderPickList}
datafieldname={datafieldname}
/>
</div> </div>
); );
} }
+64
View File
@@ -0,0 +1,64 @@
import Link from "next/link";
import { useRouter } from "next/router";
import useTranslation from "next-translate/useTranslation";
import xpath from "xpath";
import BuildField from "./buildfield";
export default function BuildCheckRow(props) {
let { t } = useTranslation();
const router = useRouter();
const { locale } = router;
const { formXML, whichSection, sectionCount, onSubmit } = props;
const parser = new DOMParser();
var doc = parser.parseFromString(props.formXML, "text/xml");
var rowXML = xpath.select(
"/form/tabs/tab[" +
whichSection +
"]/columns//sections/section/rows/row",
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);
console.log(props.form);
return (
<div className="govuk-summary-list__row" key={key}>
<dt className="govuk-summary-list__key">
{rows[0].value}
</dt>
<dd className="govuk-summary-list__value">
{
props.props.form["appealForm"].values[
datafieldname[0].value
]
}
</dd>
<dd className="govuk-summary-list__actions">
<a className="govuk-link" href="#">
Change
<span className="govuk-visually-hidden">
{" "}
name
</span>
</a>
</dd>
</div>
);
})}
</>
);
}
+121
View File
@@ -0,0 +1,121 @@
import Link from "next/link";
import { useRouter } from "next/router";
import useTranslation from "next-translate/useTranslation";
import { useState, useEffect } from "react";
import xpath from "xpath";
import BuildCheckRow from "./buildcheckrow";
import { reduxForm, formValueSelector } from "redux-form";
import { useDispatch, useSelector, shallowEqual, connect } from "react-redux";
import { setCurrentSection } from "../../store/appealType/action";
let BuildCheckSection = (props) => {
// useEffect(() => {
// window.scrollTo(0, 0);
// });
let { t } = useTranslation();
const router = useRouter();
const { locale } = router;
const {
formXML,
sectionCount,
onSubmit,
handleSubmit,
formTitle,
setCurrentSection,
} = props;
const parser = new DOMParser();
var doc = parser.parseFromString(props.formXML, "text/xml");
var titles = xpath.select(
"//form/tabs/tab[*]/labels/label/@description",
doc
);
var rowXML = xpath.select(
"/form/tabs/tab[*]/columns//sections/section/rows/row",
doc
);
var titleList = xpath.select(
"//form/tabs/tab[*]/labels/label/@description",
doc
);
const handleParam = (setValue) => (e) => setValue(e.target.value);
const basicSearch = (event) => {
event.preventDefault();
console.log(query);
// /searchresults
};
return (
<div className="govuk-grid-row">
<div className="govuk-grid-column-two-thirds">
<div>
<h1 className="govuk-heading-m">
Are these answers correct?
</h1>
{Object.keys(titles).map((key) => (
<>
<h2 className="govuk-heading-m">
{titles[key].value}
</h2>
<dl className="govuk-summary-list govuk-!-margin-bottom-9">
<BuildCheckRow
formXML={formXML}
whichSection={parseInt(key) + 1}
sectionCount={key}
props={props}
/>
</dl>
</>
))}
<dl className="govuk-summary-list govuk-!-margin-bottom-9 at-summary-list"></dl>
</div>
<div className="govuk-button-group">
<a
className="govuk-button"
data-module="govuk-button"
onClick={() => setCurrentSection(9999)}
>
Submit appeal
</a>
</div>
</div>
<div className="govuk-grid-column-one-third"></div>
</div>
);
};
const mapStateToProps = (state) => {
return {
search: state.search,
searchResultsObj: state.searchResultsObj,
formData: state.formData,
appealType: state.appealType,
form: state.form,
};
};
const mapDispatchToProps = (dispatch) => {
return {
setCurrentSection: (currentSection) => {
dispatch(setCurrentSection(currentSection));
},
};
};
// BuildCheckSection = reduxForm({
// // a unique name for the form
// form: "sssappealForm",
// destroyOnUnmount: false,
// })(BuildCheckSection);
const selector = formValueSelector("appealForm"); // <-- same as form name
export default connect(mapStateToProps, mapDispatchToProps)(BuildCheckSection);
+42 -15
View File
@@ -6,6 +6,7 @@ import xpath from "xpath";
import BuildRow from "./buildrow"; import BuildRow from "./buildrow";
import { reduxForm, formValueSelector } from "redux-form"; import { reduxForm, formValueSelector } from "redux-form";
import { useDispatch, useSelector, shallowEqual, connect } from "react-redux"; import { useDispatch, useSelector, shallowEqual, connect } from "react-redux";
import { setCurrentSection } from "../../store/appealType/action";
let BuildSection = (props) => { let BuildSection = (props) => {
// useEffect(() => { // useEffect(() => {
@@ -17,9 +18,16 @@ let BuildSection = (props) => {
const router = useRouter(); const router = useRouter();
const { locale } = router; const { locale } = router;
const { formXML, sectionCount, onSubmit, handleSubmit, formTitle } = props; const {
const [currentSection, setCurrentSection] = useState(1); formXML,
sectionCount,
onSubmit,
handleSubmit,
formTitle,
setCurrentSection,
} = props;
const currentSection = props.appealType.currentSection;
const parser = new DOMParser(); const parser = new DOMParser();
var doc = parser.parseFromString(props.formXML, "text/xml"); var doc = parser.parseFromString(props.formXML, "text/xml");
var titles = xpath.select( var titles = xpath.select(
@@ -40,12 +48,6 @@ let BuildSection = (props) => {
const handleParam = (setValue) => (e) => setValue(e.target.value); const handleParam = (setValue) => (e) => setValue(e.target.value);
const basicSearch = (event) => {
event.preventDefault();
console.log(query);
// /searchresults
};
const onHandleSubmit = (values) => { const onHandleSubmit = (values) => {
setCurrentSection(currentSection + 1); setCurrentSection(currentSection + 1);
}; };
@@ -76,6 +78,17 @@ let BuildSection = (props) => {
) : ( ) : (
"" ""
)} )}
{props.sectionCount == currentSection ? (
<button
type="submit"
className="govuk-button"
data-module="govuk-button"
>
Submit
</button>
) : (
""
)}
{currentSection > 1 ? ( {currentSection > 1 ? (
<a <a
className="govuk-link" className="govuk-link"
@@ -128,16 +141,30 @@ let BuildSection = (props) => {
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
return { return {
form: state.form, search: state.search,
searchResultsObj: state.searchResultsObj,
formData: state.formData,
appealType: state.appealType,
//form: state.form,
}; };
}; };
BuildSection = reduxForm({ const mapDispatchToProps = (dispatch) => {
// a unique name for the form return {
form: "sssappealForm", setCurrentSection: (currentSection) => {
destroyOnUnmount: false, dispatch(setCurrentSection(currentSection));
})(BuildSection); },
};
};
const selector = formValueSelector("appealForm"); // <-- same as form name const selector = formValueSelector("appealForm"); // <-- same as form name
export default connect(mapStateToProps)(BuildSection); export default connect(
mapStateToProps,
mapDispatchToProps
)(
reduxForm({
form: "appealForm",
destroyOnUnmount: false,
})(BuildSection)
);
+124
View File
@@ -0,0 +1,124 @@
import Link from "next/link";
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 { useDispatch, useSelector, shallowEqual, connect } from "react-redux";
import { setCurrentSection } from "../../store/appealType/action";
let CompleteAppeal = (props) => {
// useEffect(() => {
// window.scrollTo(0, 0);
// });
let { t } = useTranslation();
const router = useRouter();
const { locale } = router;
const {
formXML,
sectionCount,
onSubmit,
handleSubmit,
formTitle,
setCurrentSection,
} = props;
const currentSection = props.appealType.currentSection;
const parser = new DOMParser();
var doc = parser.parseFromString(props.formXML, "text/xml");
var titles = xpath.select(
"//form/tabs/tab[" + currentSection + " ]/labels/label/@description",
doc
);
var rowXML = xpath.select(
"/form/tabs/tab[" +
currentSection +
"]/columns//sections/section/rows/row",
doc
);
var titleList = xpath.select(
"//form/tabs/tab[*]/labels/label/@description",
doc
);
const handleParam = (setValue) => (e) => setValue(e.target.value);
const onHandleSubmit = (values) => {
setCurrentSection(currentSection + 1);
};
return (
<div className="govuk-grid-row">
<div className="govuk-grid-column-two-thirds">
<div className="govuk-panel govuk-panel--confirmation">
<h1 className="govuk-panel__title">Appeal complete</h1>
<div className="govuk-panel__body">
Your reference number
<br />
<strong>CAS-00010-J9W6L5</strong>
</div>
</div>
<p className="govuk-body">
We have sent you a confirmation email.
</p>
<h2 className="govuk-heading-m">What happens next</h2>
<p className="govuk-body">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Morbi a metus non quam mollis egestas. Integer ac leo
cursus, laoreet nulla sed, tempus tellus. Mauris condimentum
erat arcu.
</p>
<p className="govuk-body">
Sed imperdiet dignissim ipsum. Orci varius natoque penatibus
et magnis dis parturient montes, nascetur ridiculus mus. In
id leo in turpis aliquam venenatis ut non erat. Ut est arcu,
luctus sit amet pretium sed, iaculis non purus. Etiam dictum
tortor commodo luctus rhoncus.
</p>
<p className="govuk-body">
<Link href="/myportal">
<a className="govuk-link">Back to My Portal</a>
</Link>
</p>
<p className="govuk-body">
<a href="#" className="govuk-link">
What did you think of this service?
</a>
(takes 30 seconds)
</p>
</div>
</div>
);
};
const mapStateToProps = (state) => {
return {
search: state.search,
searchResultsObj: state.searchResultsObj,
formData: state.formData,
appealType: state.appealType,
//form: state.form,
};
};
const mapDispatchToProps = (dispatch) => {
return {
setCurrentSection: (currentSection) => {
dispatch(setCurrentSection(currentSection));
},
};
};
const selector = formValueSelector("appealForm"); // <-- same as form name
export default connect(mapStateToProps, mapDispatchToProps)(CompleteAppeal);
+2 -2
View File
@@ -5,7 +5,7 @@
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
"build": "next build", "build": "next build",
"start": "next start" "start": "node_modules/next/dist/bin/next start -p $PORT"
}, },
"dependencies": { "dependencies": {
"@webdeb/next-styles": "^1.1.1", "@webdeb/next-styles": "^1.1.1",
@@ -46,4 +46,4 @@
"eslint-config-next": "^11.0.1", "eslint-config-next": "^11.0.1",
"prettier": "2.3.2" "prettier": "2.3.2"
} }
} }
+16
View File
@@ -0,0 +1,16 @@
function Error({ statusCode }) {
return (
<p>
{statusCode
? `An error ${statusCode} occurred on server`
: "An error occurred on client"}
</p>
);
}
Error.getInitialProps = ({ res, err }) => {
const statusCode = res ? res.statusCode : err ? err.statusCode : 404;
return { statusCode };
};
export default Error;
+24 -30
View File
@@ -14,7 +14,6 @@ import { useRouter } from "next/router";
import useTranslation from "next-translate/useTranslation"; import useTranslation from "next-translate/useTranslation";
import jsonpath from "jsonpath"; import jsonpath from "jsonpath";
import { useEffect } from "react"; import { useEffect } from "react";
import { import {
setAppealType, setAppealType,
setAppealTypeTitle, setAppealTypeTitle,
@@ -25,14 +24,17 @@ import { setForm, getFormObj } from "../../store/formData/action";
import { getFormData, getAppealsTypes } from "../../actions"; import { getFormData, getAppealsTypes } from "../../actions";
import xpath from "xpath"; import xpath from "xpath";
import { reduxForm } from "redux-form"; import { reduxForm, FormName } from "redux-form";
import BuildSection from "../../components/newappeal/buildsection"; import BuildSection from "../../components/newappeal/buildsection";
import BuildCheckSection from "../../components/newappeal/buildchecksection";
import CompleteAppeal from "../../components/newappeal/complete";
let Home = (props) => { let Home = (props) => {
useEffect(() => { useEffect(() => {
props.setFormTitle(formTitle); props.setFormTitle(formTitle);
}, []); }, []);
const { footerLinks, pages, formData } = props; const { footerLinks, pages, formData } = props;
let { t, lang } = useTranslation(); let { t, lang } = useTranslation();
@@ -111,12 +113,26 @@ let Home = (props) => {
<Banner /> <Banner />
<Breadcrumbs slug={appealtypes} formTitle={formTitle} /> <Breadcrumbs slug={appealtypes} formTitle={formTitle} />
<BuildSection {props.appealType.currentSection == 9999 ? (
formXML={formXML} <CompleteAppeal />
sectionCount={sectionCount} ) : props.appealType.currentSection == sectionCount + 1 ? (
onSubmit={onSubmit} <BuildCheckSection
formTitle={formTitle} formXML={formXML}
/> sectionCount={sectionCount}
onSubmit={onSubmit}
formTitle={formTitle}
appealType={props.appealType}
props={props}
/>
) : (
<BuildSection
formXML={formXML}
sectionCount={sectionCount}
onSubmit={onSubmit}
formTitle={formTitle}
props={props}
/>
)}
</div> </div>
<Footer footerLinks={footerLinks} /> <Footer footerLinks={footerLinks} />
</div> </div>
@@ -140,28 +156,6 @@ export const getServerSideProps = wrapper.getServerSideProps(
} }
); );
// export const getServerSideProps = wrapper.getServerSideProps(
// async ({ locale, store, query, req, res }) => {
// // const token = await getToken();
// // let accessToken = token.access_token;
// // const apiRoot = process.browser ? window.API_ROOT : process.env.API_ROOT;
// // const [pages, footerLinks, courseListContent] = await Promise.all([
// // await getPages(accessToken, locale),
// // await getFooterLinks(accessToken, locale),
// // await getCourseList(accessToken, locale),
// // ]);
// // //const courseID = await getCourseID
// // store.dispatch(setApiRoot(apiRoot));
// // store.dispatch(setPages(pages));
// // store.dispatch(setFooterLinks(footerLinks));
// // store.dispatch(setCourseListContent(courseListContent));
// console.log(query);
// //store.dispatch(setSearch(query.search));
// }
// );
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
return { return {
search: state.search, search: state.search,
+7
View File
@@ -6,6 +6,7 @@ export const appealTypeDataActionTypes = {
SETAPPEALTYPEIDDATA: "SETAPPEALTYPEIDDATA", SETAPPEALTYPEIDDATA: "SETAPPEALTYPEIDDATA",
SETAPPEALTYPETITLEDATA: "SETAPPEALTYPETITLEDATA", SETAPPEALTYPETITLEDATA: "SETAPPEALTYPETITLEDATA",
UPDATEAPPEALTYPEDATA: "UPDATEAPPEALTYPEDATA", UPDATEAPPEALTYPEDATA: "UPDATEAPPEALTYPEDATA",
SETCURRENTSECTION: "SETCURRENTSECTION",
}; };
export const getAppealTypeObj = () => (dispatch) => { export const getAppealTypeObj = () => (dispatch) => {
@@ -34,3 +35,9 @@ export const setAppealTypeID = (appealTypeData) => (dispatch) => {
appealTypeID: appealTypeData, appealTypeID: appealTypeData,
}); });
}; };
export const setCurrentSection = (currentSection) => (dispatch) => {
return dispatch({
type: appealTypeDataActionTypes.SETCURRENTSECTION,
currentSection: currentSection,
});
};
+6
View File
@@ -4,6 +4,7 @@ const appealTypeDataInitialState = {
appealTypeOptions: {}, appealTypeOptions: {},
appealTypeTitle: {}, appealTypeTitle: {},
appealTypeID: {}, appealTypeID: {},
currentSection: 1,
}; };
export default function reducer(state = appealTypeDataInitialState, action) { export default function reducer(state = appealTypeDataInitialState, action) {
@@ -23,6 +24,11 @@ export default function reducer(state = appealTypeDataInitialState, action) {
...state, ...state,
appealTypeID: action.appealTypeID, appealTypeID: action.appealTypeID,
}; };
case appealTypeDataActionTypes.SETCURRENTSECTION:
return {
...state,
currentSection: action.currentSection,
};
default: default:
return state; return state;
} }
+4
View File
@@ -240,3 +240,7 @@ nav {
text-align: center; text-align: center;
} }
} }
.govuk-summary-list__key {
width: 45%;
}