Skip to content

Commit

Permalink
Questionnaire introduction
Browse files Browse the repository at this point in the history
Introduce new questionnaire introduction for all business surveys.
Add introduction and default metadata for existing business surveys.

Notable changes
1. Create Reorder component for re-ordering answers and collapsibles.
2. Add test to ensure that migrations are deterministic.
3. After discovering an issue with jsondiffpatch where array items where
being added when a patch was applied when they already existed. We have
to check if the patch needs to be applied before applying it when
dealing with conflicts in dynamo datastore.
  • Loading branch information
tgandrews committed Apr 18, 2019
1 parent cb2447f commit 33211c0
Show file tree
Hide file tree
Showing 134 changed files with 4,823 additions and 667 deletions.
3 changes: 3 additions & 0 deletions eq-author-api/constants/legalBases.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports.NOTICE_1 = "NOTICE_1";
module.exports.NOTICE_2 = "NOTICE_2";
module.exports.VOLUNTARY = "VOLUNTARY";
3 changes: 3 additions & 0 deletions eq-author-api/db/models/DynamoDB.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ const baseQuestionnaireSchema = {
shortTitle: {
type: String,
},
introduction: {
type: Object,
},
};

const questionnanaireSchema = new dynamoose.Schema(
Expand Down
32 changes: 32 additions & 0 deletions eq-author-api/migrations/addBusinessQuestionnaireIntroduction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//This is an auto-generated file. Do NOT modify the method signature.

const { find } = require("lodash");
const { BUSINESS } = require("../constants/questionnaireTypes");
const {
createDefaultBusinessSurveyMetadata,
} = require("../utils/defaultMetadata");
const {
createQuestionnaireIntroduction,
} = require("../schema/resolvers/questionnaireIntroduction");

module.exports = function addBusinessQuestionnaireIntroduction(questionnaire) {
if (questionnaire.type !== BUSINESS) {
return questionnaire;
}

const defaultMetadata = createDefaultBusinessSurveyMetadata();
const metadataToAdd = defaultMetadata
.filter(({ key }) => !find(questionnaire.metadata, { key }))
.map((md, index) => ({
...md,
id: `migrated-md-${index}`,
}));
questionnaire.metadata = [...questionnaire.metadata, ...metadataToAdd];

questionnaire.introduction = createQuestionnaireIntroduction(
questionnaire.metadata
);
questionnaire.introduction.id = "questionnaire-introduction";

return questionnaire;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
const { cloneDeep } = require("lodash");

const { SOCIAL, BUSINESS } = require("../constants/questionnaireTypes");

const addBusinessQuestionnaireIntroduction = require("./addBusinessQuestionnaireIntroduction.js");

describe("addBusinessQuestionnaireIntroduction", () => {
it("should be deterministic", () => {
const questionnaire = {
type: BUSINESS,
metadata: [],
};

expect(
addBusinessQuestionnaireIntroduction(cloneDeep(questionnaire))
).toMatchObject(
addBusinessQuestionnaireIntroduction(cloneDeep(questionnaire))
);
});

it("should not touch social", () => {
const questionnaire = {
type: SOCIAL,
};

expect(addBusinessQuestionnaireIntroduction(questionnaire)).toEqual(
questionnaire
);
});

it("should add missing default metadata", () => {
const questionnaire = {
type: BUSINESS,
metadata: [
{
key: "ru_name",
alias: "Ru Name",
type: "Text",
value: "ESSENTIAL ENTERPRISE LTD.",
},
],
};

expect(
addBusinessQuestionnaireIntroduction(questionnaire).metadata.map(
md => md.key
)
).toEqual([
"ru_name",
"trad_as",
"period_id",
"ref_p_start_date",
"ref_p_end_date",
"employmentDate",
]);
});
});
2 changes: 2 additions & 0 deletions eq-author-api/migrations/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ const addVersion = require("./addVersion");
const addOptionalFieldProperties = require("./addOptionalFieldProperties");
const addQuestionnaireType = require("./addQuestionnaireType");
const updateMetadataValue = require("./updateMetadataValue");
const addBusinessQuestionnaireIntroduction = require("./addBusinessQuestionnaireIntroduction");

const migrations = [
addVersion,
addOptionalFieldProperties,
addQuestionnaireType,
updateMetadataValue,
addBusinessQuestionnaireIntroduction,
];

const currentVersion = migrations.length;
Expand Down
56 changes: 39 additions & 17 deletions eq-author-api/schema/resolvers/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const {
} = require("../../utils/datastore");

const {
defaultBusinessSurveyMetadata,
createDefaultBusinessSurveyMetadata,
} = require("../../utils/defaultMetadata");

const { listQuestionnaires } = require("../../utils/datastore");
Expand All @@ -64,6 +64,11 @@ const { DATE, DATE_RANGE } = require("../../constants/answerTypes");
const { DATE: METADATA_DATE } = require("../../constants/metadataTypes");
const { VALIDATION_TYPES } = require("../../constants/validationTypes");

const {
createQuestionnaireIntroduction,
} = require("./questionnaireIntroduction");


const getQuestionnaireList = () => {
return listQuestionnaires();
};
Expand Down Expand Up @@ -131,22 +136,39 @@ const createSection = (input = {}) => ({
...input,
});

const createNewQuestionnaire = input => ({
id: uuid.v4(),
title: null,
description: null,
theme: "default",
legalBasis: "Voluntary",
navigation: false,
surveyId: "",
createdAt: new Date(),
metadata: input.type === BUSINESS ? defaultBusinessSurveyMetadata : [],
sections: [createSection()],
summary: false,
version: currentVersion,
shortTitle: "",
...input,
});
const createNewQuestionnaire = input => {
const defaultQuestionnaire = {
id: uuid.v4(),
title: null,
description: null,
theme: "default",
legalBasis: "Voluntary",
navigation: false,
surveyId: "",
createdAt: new Date(),
metadata: [],
sections: [createSection()],
summary: false,
version: currentVersion,
shortTitle: "",
introduction: null,
};

let changes = {};
if (input.type === BUSINESS) {
const metadata = createDefaultBusinessSurveyMetadata();
changes = {
metadata,
introduction: createQuestionnaireIntroduction(metadata),
};
}

return {
...defaultQuestionnaire,
...changes,
...input,
};
};

const Resolvers = {
Query: {
Expand Down
3 changes: 2 additions & 1 deletion eq-author-api/schema/resolvers/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const base = require("./base");
const routing2 = require("./routing2");
const page = require("./pages");
const questionnaireIntroduction = require("./questionnaireIntroduction");

module.exports = [base, ...routing2, ...page];
module.exports = [base, ...routing2, ...page, ...questionnaireIntroduction];
83 changes: 83 additions & 0 deletions eq-author-api/schema/resolvers/questionnaireIntroduction.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
const { find, omit, first, remove } = require("lodash");
const uuid = require("uuid").v4;

const { saveQuestionnaire } = require("../../utils/datastore");
const { NOTICE_1 } = require("../../constants/legalBases");

const createCollapsible = options => ({
id: uuid(),
title: "",
description: "",
...options,
});

const Resolvers = {};
Resolvers.Query = {
questionnaireIntroduction: (root, args, ctx) =>
ctx.questionnaire.introduction,
};
Resolvers.Mutation = {
updateQuestionnaireIntroduction: async (_, { input }, ctx) => {
const introduction = ctx.questionnaire.introduction;
Object.assign(introduction, omit(input, "id"));
await saveQuestionnaire(ctx.questionnaire);
return introduction;
},
createCollapsible: async (_, { input }, ctx) => {
const collapsible = createCollapsible(omit(input, "introductionId"));
ctx.questionnaire.introduction.collapsibles.push(collapsible);
await saveQuestionnaire(ctx.questionnaire);
return collapsible;
},
updateCollapsible: async (_, { input: { id, ...rest } }, ctx) => {
const collapsible = ctx.questionnaire.introduction.collapsibles.find(
c => c.id === id
);
Object.assign(collapsible, rest);
await saveQuestionnaire(ctx.questionnaire);
return collapsible;
},
moveCollapsible: async (_, { input: { id, position } }, ctx) => {
const introduction = ctx.questionnaire.introduction;
const collapsibleMoving = first(remove(introduction.collapsibles, { id }));
introduction.collapsibles.splice(position, 0, collapsibleMoving);
await saveQuestionnaire(ctx.questionnaire);
return collapsibleMoving;
},
deleteCollapsible: async (_, { input: { id } }, ctx) => {
const introduction = ctx.questionnaire.introduction;
remove(introduction.collapsibles, { id });
await saveQuestionnaire(ctx.questionnaire);
return introduction;
},
};
Resolvers.QuestionnaireIntroduction = {
availablePipingMetadata: (root, args, ctx) => ctx.questionnaire.metadata,
availablePipingAnswers: () => [],
};

Resolvers.Collapsible = {
introduction: (root, args, ctx) => ctx.questionnaire.introduction,
};

module.exports = [Resolvers];
module.exports.createQuestionnaireIntroduction = metadata => {
return {
id: uuid.v4(),
title: `<p>You are completing this for <span data-piped="metadata" data-id="${
find(metadata, { key: "trad_as" }).id
}">trad_as</span> (<span data-piped="metadata" data-id="${
find(metadata, { key: "ru_name" }).id
}">ru_name</span>)</p>`,
description:
"<ul><li>Data should relate to all sites in England, Scotland, Wales and Northern Ireland unless otherwise stated. </li><li>You can provide info estimates if actual figures aren’t available.</li><li>We will treat your data securely and confidentially.</li></ul>",
legalBasis: NOTICE_1,
secondaryTitle: "<p>Information you need</p>",
secondaryDescription:
"<p>You can select the dates of the period you are reporting for, if the given dates are not appropriate.</p>",
collapsibles: [],
tertiaryTitle: "<p>How we use your data</p>",
tertiaryDescription:
"<ul><li>You cannot appeal your selection. Your business was selected to give us a comprehensive view of the UK economy.</li><li>The information you provide contributes to Gross Domestic Product (GDP).</li></ul>",
};
};
Loading

0 comments on commit 33211c0

Please sign in to comment.