Skip to content

Commit

Permalink
Merge pull request #3120 from ONSdigital/EAR-2291-Update-content-for-…
Browse files Browse the repository at this point in the history
…calculated-summary-questions

EAR 2291 update content for calculated summary questions
  • Loading branch information
Farhanam76 authored Jul 5, 2024
2 parents 7e0ebb7 + a556e96 commit a9a4d94
Show file tree
Hide file tree
Showing 2 changed files with 263 additions and 22 deletions.
167 changes: 145 additions & 22 deletions eq-author/src/App/page/Preview/CalculatedSummaryPreview.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { propType } from "graphql-anywhere";
import styled from "styled-components";
import Error from "components/preview/Error";
import PageTitle from "components/preview/elements/PageTitle";
import Info from "components/preview/elements/Info";

import EditorLayout from "components/EditorLayout";
import Panel from "components/Panel";
Expand All @@ -15,6 +14,8 @@ import CommentsPanel from "App/Comments";
import { colors } from "constants/theme";
import CalculatedSummaryPageEditor from "../Design/CalculatedSummaryPageEditor";
import { useSetNavigationCallbacksForPage } from "components/NavigationCallbacks";
import { getPageByAnswerId } from "utils/questionnaireUtils";
import { useQuestionnaire } from "components/QuestionnaireContext";

const Container = styled.div`
padding: 2em;
Expand All @@ -32,17 +33,34 @@ const Container = styled.div`
white-space: pre-wrap;
}
`;
const Button = styled.div`
color: white;
background-color: ${colors.green};
border: 2px solid ${colors.green};
padding: 0.75rem 1rem;
margin: 0;
font-size: 1rem;
font-weight: 600;
border-radius: 3px;
display: inline-block;
text-rendering: optimizeLegibility;
margin-bottom: 2em;
`;

const Summary = styled.div`
border-bottom: 1px solid #999;
margin-bottom: 2rem;
`;

const SummaryItem = styled.div`
border-top: 1px solid #999;
border-radius: 0;
position: relative;
padding: 1rem 0;
border-bottom: ${(props) =>
props.isLastSummaryAnswerFromPage ? "1px solid #999" : "none"};
`;

const QuestionPageTitle = styled.div`
margin-bottom: 1rem;
`;

const SummaryLabel = styled.div`
Expand Down Expand Up @@ -78,12 +96,74 @@ const SummaryTotalLabel = styled.div`
`;

const CalculatedSummaryPagePreview = ({ page }) => {
const { questionnaire } = useQuestionnaire();
useSetNavigationCallbacksForPage({
page: page,
folder: page?.folder,
section: page?.section,
});

const usedPageIds = [];

const getAnswerIndexInPage = (answer) => {
const page = getPageByAnswerId(questionnaire, answer.id);

// Finds the index of the answer argument within its page
return page?.answers?.findIndex(
(pageAnswer) => pageAnswer.id === answer.id
);
};

/*
Sorts summaryAnswers by page and answers (keeps pages in the order they appear in summaryAnswers, and sorts answers by their order in their page)
Ensures answers are always displayed underneath their page, and in the order they appear in the page
.slice() creates a copy of page.summaryAnswers to prevent mutating the original page.summaryAnswers array
*/
const sortedSummaryAnswers = page.summaryAnswers.slice().sort((a, b) => {
const pageContainingAnswerA = getPageByAnswerId(questionnaire, a.id);
const pageContainingAnswerB = getPageByAnswerId(questionnaire, b.id);

// If the answers are on the same page, sort the answers in the order they appear in the page
if (pageContainingAnswerA?.id === pageContainingAnswerB?.id) {
return getAnswerIndexInPage(a) - getAnswerIndexInPage(b);
}

// Gets the first answer from page A that appears in summaryAnswers
const firstAnswerFromPageA = page.summaryAnswers.find(
(answer) =>
getPageByAnswerId(questionnaire, answer.id)?.id ===
pageContainingAnswerA?.id
);
// Gets the first answer from page B that appears in summaryAnswers
const firstAnswerFromPageB = page.summaryAnswers.find(
(answer) =>
getPageByAnswerId(questionnaire, answer.id)?.id ===
pageContainingAnswerB?.id
);

// Sorts answers based on the order of their pages in summaryAnswers (keeps pages in the order they appear in summaryAnswers)
return (
page.summaryAnswers.indexOf(firstAnswerFromPageA) -
page.summaryAnswers.indexOf(firstAnswerFromPageB)
);
});

const getDuplicatedPageIds = () => {
const allPageIds = [];

sortedSummaryAnswers.forEach((summaryAnswer) => {
const summaryAnswerPage = getPageByAnswerId(
questionnaire,
summaryAnswer.id
);
allPageIds.push(summaryAnswerPage?.id);
});

return allPageIds.filter(
(pageId, index) => allPageIds.indexOf(pageId) !== index
);
};

return (
<EditorLayout
title={page.displayName}
Expand All @@ -98,27 +178,69 @@ const CalculatedSummaryPagePreview = ({ page }) => {
<Panel data-test="calSum test page">
<Container>
<PageTitle title={page.title} />
<Info>Please review your answers and confirm these are correct.</Info>

{page.summaryAnswers.length > 0 ? (
{sortedSummaryAnswers.length > 0 ? (
<Summary>
{page.summaryAnswers.map((answer) => (
<SummaryItem key={answer.id}>
<Grid>
<Column cols={7}>
<SummaryLabel data-test="answer-item">
{answer.displayName}
</SummaryLabel>
</Column>
<Column cols={3}>
<SummaryValue>Value</SummaryValue>
</Column>
<Column cols={2}>
<SummaryLink>Change</SummaryLink>
</Column>
</Grid>
</SummaryItem>
))}
{sortedSummaryAnswers.map((answer, index) => {
const answerPage = getPageByAnswerId(questionnaire, answer.id);
const hasAnswerPageIdBeenUsed = usedPageIds.includes(
answerPage?.id
);

if (!hasAnswerPageIdBeenUsed) {
usedPageIds.push(answerPage?.id);
}

const duplicatedPageIds = getDuplicatedPageIds();
const questionTitle = answerPage?.title.replace(
/<p>|<\/p>/g,
""
);

const summaryAnswersOnSamePage = sortedSummaryAnswers.filter(
(summaryAnswer) =>
getPageByAnswerId(questionnaire, summaryAnswer.id)?.id ===
answerPage?.id
);
const lastSummaryAnswerFromPage =
summaryAnswersOnSamePage[summaryAnswersOnSamePage.length - 1];

const isLastSummaryAnswerFromPage =
answer.id === lastSummaryAnswerFromPage.id;

return (
<SummaryItem
key={answer.id}
isLastSummaryAnswerFromPage={isLastSummaryAnswerFromPage}
>
{!hasAnswerPageIdBeenUsed &&
duplicatedPageIds.includes(answerPage?.id) && (
<QuestionPageTitle
data-test={`question-title-${duplicatedPageIds?.findIndex(
(pageId) => pageId === answerPage?.id
)}`}
questionTitle={questionTitle}
>
{questionTitle}
</QuestionPageTitle>
)}

<Grid>
<Column cols={7}>
<SummaryLabel data-test={`answer-item-${index}`}>
{answer.displayName}
</SummaryLabel>
</Column>
<Column cols={3}>
<SummaryValue>Value</SummaryValue>
</Column>
<Column cols={2}>
<SummaryLink>Change</SummaryLink>
</Column>
</Grid>
</SummaryItem>
);
})}

{page.totalTitle ? (
<SummaryTotal>
Expand Down Expand Up @@ -148,6 +270,7 @@ const CalculatedSummaryPagePreview = ({ page }) => {
No answers selected
</Error>
)}
<Button>Yes, I confirm this is correct</Button>
</Container>
</Panel>
</EditorLayout>
Expand Down
118 changes: 118 additions & 0 deletions eq-author/src/App/page/Preview/CalculatedSummaryPreview.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,101 @@ import { render, flushPromises, act } from "tests/utils/rtl";

import commentsSubscription from "graphql/subscriptions/commentSubscription.graphql";
import { MeContext } from "App/MeContext";

import { byTestAttr } from "tests/utils/selectors";

import CalculatedSummaryPreview from "./CalculatedSummaryPreview";
import { publishStatusSubscription } from "components/EditorLayout/Header";
import QuestionnaireContext from "components/QuestionnaireContext";

jest.mock("@apollo/react-hooks", () => ({
...jest.requireActual("@apollo/react-hooks"),
useQuery: jest.fn(),
useMutation: jest.fn(() => [() => null]),
}));

const questionnaire = {
id: "questionnaire-1",
sections: [
{
id: "section-1",
folders: [
{
id: "folder-1",
pages: [
{
id: "3",
pageType: "QuestionPage",
title: "Page 1",
answers: [
{
id: "answer-1",
label: "answer 1",
},
{
id: "answer-2",
label: "answer 2",
},
],
},
{
id: "6",
pageType: "QuestionPage",
title: "Page 2",
answers: [
{
id: "answer-3",
label: "answer 3",
},
{
id: "answer-4",
label: "answer 4",
},
],
},
{
id: "9",
displayName: "Cal Sum",
position: 1,
title: "Calculated summary page 1",
totalTitle: "Total bills:",
pageDescription: "This page calculates the total bills",
alias: "Who am I?",
type: "Number",
answers: [],
comments: [],

summaryAnswers: [
{ id: "answer-4", displayName: "Answer 4" },
{ id: "answer-2", displayName: "Answer 2" },
{ id: "answer-3", displayName: "Answer 3" },
{ id: "answer-1", displayName: "Answer 1" },
],
pageType: "CalculatedSummaryPage",
section: {
id: "1",
position: 0,
questionnaire: {
id: "1",
metadata: [],
},
},
validationErrorInfo: {
id: "test",
totalCount: 0,
errors: [],
},
folder: {
id: "folder-1",
position: 0,
},
},
],
},
],
},
],
};

describe("CalculatedSummaryPreview", () => {
let page, me, mocks, questionnaireId;
Expand Down Expand Up @@ -133,4 +224,31 @@ describe("CalculatedSummaryPreview", () => {
);
expect(wrapper.find(byTestAttr("no-answers-selected"))).toBeTruthy();
});

it("should sort the summary answers based on the first selection and ensure that the display names and question titles match this order", () => {
const { getByTestId } = render(
<QuestionnaireContext.Provider value={{ questionnaire }}>
<MeContext.Provider value={{ me }}>
<CalculatedSummaryPreview
page={questionnaire.sections[0].folders[0].pages[2]}
/>
</MeContext.Provider>
,
</QuestionnaireContext.Provider>,
{
route: `/q/${questionnaireId}/page/9/preview`,
urlParamMatcher: "/q/:questionnaireId/page/:pageId",
mocks,
}
);
expect(getByTestId("question-title-0")).toHaveTextContent("Page 2");

expect(getByTestId("answer-item-0")).toHaveTextContent("Answer 3");
expect(getByTestId("answer-item-1")).toHaveTextContent("Answer 4");

expect(getByTestId("question-title-1")).toHaveTextContent("Page 1");

expect(getByTestId("answer-item-2")).toHaveTextContent("Answer 1");
expect(getByTestId("answer-item-3")).toHaveTextContent("Answer 2");
});
});

0 comments on commit a9a4d94

Please sign in to comment.