Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: update Confirmation banner description to use rich text & reword details #3545

Merged
merged 2 commits into from
Aug 22, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,6 @@ export const Basic = {
description: `A payment receipt has been emailed to you. You will also
receive an email to confirm when your application has been received.`,
color: { background: "rgba(1, 99, 96, 0.1)", text: "#000" },
details: {
"Planning Application Reference": "LBL–LDCP-2138261",
"Property Address": "45, Greenfield Road, London SE22 7FF",
"Application type":
"Application for a Certificate of Lawfulness – Proposed",
Submitted: new Date().toLocaleDateString("en-gb", {
day: "numeric",
month: "long",
year: "numeric",
}),
"GOV.UK Payment reference": "qe817o3kds9474rfkfldfHSK874JB",
},
nextSteps: [
{ title: "Validation", description: "Something will be validated" },
{ title: "Site visit", description: "Someone will visit" },
Expand Down
12 changes: 8 additions & 4 deletions editor.planx.uk/src/@planx/components/Confirmation/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { Confirmation, parseNextSteps, Step } from "./model";

export type Props = EditorProps<TYPES.Confirmation, Confirmation>;

function StepEditor(props: ListManagerEditorProps<Step>) {
function NextStepEditor(props: ListManagerEditorProps<Step>) {
return (
<Box width="100%">
<InputRow>
Expand Down Expand Up @@ -55,10 +55,14 @@ export default function ConfirmationEditor(props: Props) {
const type = TYPES.Confirmation;
const formik = useFormik({
initialValues: {
color: props.node?.color || {
text: "#000",
background: "rgba(1, 99, 96, 0.1)",
},
heading: props.node?.data?.heading || "Application sent",
description:
props.node?.data?.description ||
`A payment receipt has been emailed to you. You will also receive an email to confirm when your application has been received.`,
`<p>A payment receipt has been emailed to you. You will also receive an email to confirm when your application has been received.</p>`,
Comment on lines +58 to +65
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the standard pattern we're using here is to put the default values into the parse<COMPONENT_TYPE>() function in the associated model.ts - a little cleaner and more consistent?

moreInfo:
props.node?.data?.moreInfo ||
`<h2>You will be contacted</h2>
Expand Down Expand Up @@ -95,7 +99,7 @@ export default function ConfirmationEditor(props: Props) {
/>
</InputRow>
<InputRow>
<Input
<RichTextInput
placeholder="Description"
name="description"
value={formik.values.description}
Expand All @@ -112,7 +116,7 @@ export default function ConfirmationEditor(props: Props) {
onChange={(steps: Step[]) => {
formik.setFieldValue("nextSteps", steps);
}}
Editor={StepEditor}
Editor={NextStepEditor}
newValue={() => ({ title: "", description: "" })}
/>
</ModalSectionContent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ jest.mock("@opensystemslab/planx-core", () => {
it("should not have any accessibility violations", async () => {
const { container } = setup(
<ConfirmationComponent
color={{ text: "#000", background: "rgba(1, 99, 96, 0.1)" }}
heading="heading"
description="description"
details={{ key1: "something", key2: "something else" }}
nextSteps={[
{ title: "title1", description: "description1" },
{ title: "title2", description: "description2" },
Expand Down
91 changes: 65 additions & 26 deletions editor.planx.uk/src/@planx/components/Confirmation/Public.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { QuestionAndResponses } from "@opensystemslab/planx-core/types";
import Card from "@planx/components/shared/Preview/Card";
import { SummaryListTable } from "@planx/components/shared/Preview/SummaryList";
import { PublicProps } from "@planx/components/ui";
import { useStore } from "pages/FlowEditor/lib/store";
import { objectWithoutNullishValues } from "lib/objectHelpers";
import { Store, useStore } from "pages/FlowEditor/lib/store";
import React, { useEffect, useState } from "react";
import Banner from "ui/public/Banner";
import FileDownload from "ui/public/FileDownload";
Expand Down Expand Up @@ -49,25 +50,14 @@ export default function ConfirmationComponent(props: Props) {
iconTitle={"Success"}
>
{props.description && (
<Box mt={4}>
<Typography maxWidth="formWrap">{props.description}</Typography>
<Box mt={2} maxWidth="formWrap">
<ReactMarkdownOrHtml source={props.description} openLinksOnNewTab />
</Box>
)}
</Banner>
<Card>
{props.details && (
<SummaryListTable>
{Object.entries(props.details).map((item) => (
<>
<Box component="dt">{item[0]}</Box>
<Box component="dd">{item[1]}</Box>
</>
))}
</SummaryListTable>
)}

{<FileDownload data={data} filename={sessionId || "application"} />}

<Details />
<FileDownload data={data} filename={sessionId || "application"} />
{props.nextSteps && Boolean(props.nextSteps?.length) && (
<Box pt={3}>
<Typography variant="h2" mb={2}>
Expand All @@ -76,7 +66,6 @@ export default function ConfirmationComponent(props: Props) {
<NumberedList items={props.nextSteps} heading="h2" />
</Box>
)}

{props.moreInfo && (
<>
<Box py={1}>
Expand All @@ -85,18 +74,68 @@ export default function ConfirmationComponent(props: Props) {
<hr />
</>
)}

{props.contactInfo && (
<>
<Box py={1}>
<Typography variant="h2" component="h3" gutterBottom>
Contact us
</Typography>
<ReactMarkdownOrHtml source={props.contactInfo} />
</Box>
</>
<Box py={1}>
<Typography variant="h2" component="h3" gutterBottom>
Contact us
</Typography>
<ReactMarkdownOrHtml source={props.contactInfo} openLinksOnNewTab />
</Box>
)}
</Card>
</Box>
);
}

function Details() {
const [sessionId, passport, govUkPayment, flowName] = useStore((state) => [
state.sessionId,
state.computePassport(),
state.govUkPayment,
state.flowName,
]);

const details = {
"Application reference": sessionId,
"Property address": passport.data?._address?.title,
"Application type": [
flowName.replace("Apply", "Application"),
getWorkStatus(passport),
]
.filter(Boolean)
.join(" - "),
"GOV.UK payment reference": govUkPayment?.payment_id,
"Paid at":
govUkPayment?.created_date &&
new Date(govUkPayment.created_date).toLocaleDateString("en-gb", {
day: "numeric",
month: "long",
year: "numeric",
}),
};
const applicableDetails = objectWithoutNullishValues(details) as Record<
string,
string
>;

return (
<SummaryListTable>
{Object.entries(applicableDetails).map(([k, v], i) => (
<React.Fragment key={`detail-${i}`}>
<Box component="dt">{k}</Box>
<Box component="dd">{v}</Box>
</React.Fragment>
))}
</SummaryListTable>
);
}

// TODO - Retire in favor of ODP Schema application type descriptions or fallback to flowName
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't want to do this yet because we know our ODP Schema enums are a bit in flux, but imagine it will be the better / more consistent way forward ! This function only does special handling for LDCs - which is fine for now as they're the only live statutory service.

function getWorkStatus(passport: Store.passport): string | undefined {
switch (passport?.data?.["application.type"]?.toString()) {
case "ldc.existing":
return "existing";
case "ldc.proposed":
return "proposed";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ export interface Confirmation {
heading?: string;
description?: string;
color?: { text: string; background: string };
details?: { [key: string]: string };
nextSteps?: Step[];
moreInfo?: string;
contactInfo?: string;
Expand Down
56 changes: 7 additions & 49 deletions editor.planx.uk/src/pages/Preview/Node.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import {
ComponentType as TYPES,
DEFAULT_FLAG_CATEGORY,
GOV_PAY_PASSPORT_KEY,
GovUKPayment,
} from "@opensystemslab/planx-core/types";
import { ComponentType as TYPES } from "@opensystemslab/planx-core/types";
import AddressInput from "@planx/components/AddressInput/Public";
import Calculate from "@planx/components/Calculate/Public";
import Checklist from "@planx/components/Checklist/Public";
Expand Down Expand Up @@ -31,7 +29,6 @@ import Send from "@planx/components/Send/Public";
import SetValue from "@planx/components/SetValue/Public";
import TaskList from "@planx/components/TaskList/Public";
import TextInput from "@planx/components/TextInput/Public";
import { objectWithoutNullishValues } from "lib/objectHelpers";
import mapAccum from "ramda/src/mapAccum";
import React from "react";

Expand Down Expand Up @@ -87,6 +84,7 @@ const Node: React.FC<any> = (props: Props) => {
switch (props.node.type) {
case TYPES.Calculate:
return <Calculate {...allProps} />;

case TYPES.Checklist: {
const childNodes = childNodesOf(props.node.id);
return (
Expand Down Expand Up @@ -114,43 +112,10 @@ const Node: React.FC<any> = (props: Props) => {
/>
);
}
case TYPES.Confirmation: {
const payment: GovUKPayment | undefined =
passport.data?.[GOV_PAY_PASSPORT_KEY];

const details = {
"Planning application reference": payment?.reference ?? sessionId,

"Property address": passport.data?._address?.title,

"Application type": [
flowName.replace("Apply", "Application"),
getWorkStatus(passport),
]
.filter(Boolean)
.join(" - "),

// XXX: If there is no payment we can't alternatively show Date.now() because it
// will change after page refresh. BOPS submission time needs to be queryable.
Submitted: payment?.created_date
? new Date(payment.created_date).toLocaleDateString("en-gb", {
day: "numeric",
month: "long",
year: "numeric",
})
: undefined,

"GOV.UK Payment reference": payment?.payment_id,
};

return (
<Confirmation
{...allProps}
details={objectWithoutNullishValues(details)}
color={{ text: "#000", background: "rgba(1, 99, 96, 0.1)" }}
/>
);
}
case TYPES.Confirmation:
return <Confirmation {...allProps} />;

case TYPES.Content:
return <Content {...allProps} />;

Expand Down Expand Up @@ -209,6 +174,7 @@ const Node: React.FC<any> = (props: Props) => {
/>
);
}

case TYPES.Review:
return <Review {...allProps} />;

Expand Down Expand Up @@ -267,6 +233,7 @@ const Node: React.FC<any> = (props: Props) => {
case TYPES.Answer:
case undefined:
return null;

default:
console.error({ nodeNotFound: props });
return exhaustiveCheck(props.node.type);
Expand All @@ -277,13 +244,4 @@ function exhaustiveCheck(type: never): never {
throw new Error(`Missing type ${type}`);
}

function getWorkStatus(passport: Store.passport): string | undefined {
switch (passport?.data?.["application.type"]?.toString()) {
case "ldc.existing":
return "existing";
case "ldc.proposed":
return "proposed";
}
}

export default Node;
Loading