From 9f3cb18bba07accb4f51ac0aa1d2e76c55fa60db Mon Sep 17 00:00:00 2001 From: Shane Edwards Date: Wed, 5 Dec 2018 17:15:33 +0000 Subject: [PATCH] Your household interviewer led - First part of journey added --- _data/your-household-interview-led.yml | 5 + _includes/footer-eq-default-minimal.html | 11 + _includes/header-eq-default.html | 2 + _layouts/eq-default-extras.html | 6 +- .../assets/household.js | 133 ++++ .../assets/numbers-to-words.js | 146 +++++ .../assets/personal-details.js | 185 ++++++ .../assets/prototype-tools.js | 140 ++++ .../assets/relationships.js | 619 ++++++++++++++++++ .../assets/utils.js | 39 ++ .../your-household-interview-led/bundle.js | 406 ++++++++++++ .../confirm-address.html | 97 +++ .../do-you-live-here.html | 137 ++++ .../your-household-interview-led/index.html | 96 +++ .../number-of-people.html | 109 +++ .../section-intro.html | 79 +++ .../your-household-interview-led/style.css | 80 +++ .../test-address.html | 229 +++++++ .../what-is-your-name.html | 139 ++++ .../who-else-to-add.html | 269 ++++++++ 20 files changed, 2926 insertions(+), 1 deletion(-) create mode 100644 _data/your-household-interview-led.yml create mode 100644 _includes/footer-eq-default-minimal.html create mode 100644 _prototypes/your-household-interview-led/assets/household.js create mode 100644 _prototypes/your-household-interview-led/assets/numbers-to-words.js create mode 100644 _prototypes/your-household-interview-led/assets/personal-details.js create mode 100644 _prototypes/your-household-interview-led/assets/prototype-tools.js create mode 100644 _prototypes/your-household-interview-led/assets/relationships.js create mode 100644 _prototypes/your-household-interview-led/assets/utils.js create mode 100644 _prototypes/your-household-interview-led/bundle.js create mode 100644 _prototypes/your-household-interview-led/confirm-address.html create mode 100644 _prototypes/your-household-interview-led/do-you-live-here.html create mode 100644 _prototypes/your-household-interview-led/index.html create mode 100644 _prototypes/your-household-interview-led/number-of-people.html create mode 100644 _prototypes/your-household-interview-led/section-intro.html create mode 100644 _prototypes/your-household-interview-led/style.css create mode 100644 _prototypes/your-household-interview-led/test-address.html create mode 100644 _prototypes/your-household-interview-led/what-is-your-name.html create mode 100644 _prototypes/your-household-interview-led/who-else-to-add.html diff --git a/_data/your-household-interview-led.yml b/_data/your-household-interview-led.yml new file mode 100644 index 0000000000..f22315174c --- /dev/null +++ b/_data/your-household-interview-led.yml @@ -0,0 +1,5 @@ +navigationItemsHousehold: +- label: People in your household + state: current +- label: Accommodation + state: incomplete diff --git a/_includes/footer-eq-default-minimal.html b/_includes/footer-eq-default-minimal.html new file mode 100644 index 0000000000..c9dbaaedb6 --- /dev/null +++ b/_includes/footer-eq-default-minimal.html @@ -0,0 +1,11 @@ + diff --git a/_includes/header-eq-default.html b/_includes/header-eq-default.html index 2933cb2d18..4ab94e14da 100644 --- a/_includes/header-eq-default.html +++ b/_includes/header-eq-default.html @@ -26,7 +26,9 @@ {{ site.title }} {% endif %} + {% unless page.hideSaveLater %} + {% endunless %} diff --git a/_layouts/eq-default-extras.html b/_layouts/eq-default-extras.html index 9cf29a8b3a..b1ee608890 100644 --- a/_layouts/eq-default-extras.html +++ b/_layouts/eq-default-extras.html @@ -21,7 +21,11 @@ {{ content }} diff --git a/_prototypes/your-household-interview-led/assets/household.js b/_prototypes/your-household-interview-led/assets/household.js new file mode 100644 index 0000000000..2fb9d62ca7 --- /dev/null +++ b/_prototypes/your-household-interview-led/assets/household.js @@ -0,0 +1,133 @@ +import {autoIncrementId} from './utils'; + +export const HOUSEHOLD_MEMBERS_STORAGE_KEY = 'household-members'; +export const USER_HOUSEHOLD_MEMBER_ID = 'person_me'; +export const HOUSEHOLD_MEMBER_TYPE = 'household-member'; +export const VISITOR_TYPE = 'visitor'; + +/** + * Types + */ +export function person(opts) { + if (opts.firstName === '' || opts.lastName === '') { + console.log('Unable to create person with data: ', + opts.firstName, + !opts.middleName, + !opts.lastName); + } + + let middleName = opts.middleName || ''; + + return { + fullName: opts.firstName + ' ' + middleName + ' ' + opts.lastName, + firstName: opts.firstName, + middleName, + lastName: opts.lastName + }; +} + +/** + * Storage + */ +export function getUserAsHouseholdMember() { + return getAllHouseholdMembers().find((member) => { + return member['@person'].id === USER_HOUSEHOLD_MEMBER_ID; + }); +} + +export function deleteUserAsHouseholdMember() { + deleteHouseholdMember(USER_HOUSEHOLD_MEMBER_ID); +} + +export function deleteHouseholdMember(personId) { + let members = getAllHouseholdMembers().filter((member) => { + return member['@person'].id !== personId; + }); + + sessionStorage.setItem(HOUSEHOLD_MEMBERS_STORAGE_KEY, + JSON.stringify(members)); +} + +export function updateUserAsHouseholdMember(person, memberData) { + let userAsHouseholdMember = getUserAsHouseholdMember(); + + person.id = USER_HOUSEHOLD_MEMBER_ID; + + userAsHouseholdMember + ? updateHouseholdMember(person, memberData) + : addHouseholdMember(person, memberData, USER_HOUSEHOLD_MEMBER_ID); +} + +export function updateHouseholdMember(person, memberData) { + let membersUpdated = getAllHouseholdMembers().map((member) => { + return member['@person'].id === person.id + ? {...member, ...memberData, '@person': {...member['@person'], ...person}} + : member; + }); + + sessionStorage.setItem(HOUSEHOLD_MEMBERS_STORAGE_KEY, + JSON.stringify(membersUpdated)); +} + +export function addHouseholdMember(person, memberData, id) { + let people = getAllHouseholdMembers() || []; + memberData = memberData || {}; + + /** + * User is always first in the household list + */ + people[id === USER_HOUSEHOLD_MEMBER_ID ? 'unshift' : 'push']({ + ...memberData, + type: memberData.type || HOUSEHOLD_MEMBER_TYPE, + '@person': { + ...person, + id: id || 'person' + autoIncrementId('household-members') + } + }); + + sessionStorage.setItem(HOUSEHOLD_MEMBERS_STORAGE_KEY, JSON.stringify(people)); +} + +export function getAllHouseholdMembers() { + return JSON.parse(sessionStorage.getItem(HOUSEHOLD_MEMBERS_STORAGE_KEY)) || []; +} + +export function getHouseholdMemberByPersonId(id) { + return getAllHouseholdMembers().find(function(member) { + return member['@person'].id === id; + }); +} + +export function getMemberPersonId(member) { + return member['@person'].id; +} + +/** + * Comparators + */ +export function isVisitor(member) { + return member.type === window.ONS.storage.KEYS.VISITOR_TYPE; +} + +export function isHouseholdMember(member) { + return member.type === window.ONS.storage.KEYS.HOUSEHOLD_MEMBER_TYPE; +} + +export function isOtherHouseholdMember(member) { + return member.type === window.ONS.storage.KEYS.HOUSEHOLD_MEMBER_TYPE && + member['@person'].id !== window.ONS.storage.IDS.USER_HOUSEHOLD_MEMBER_ID; +} + +export const tempAwayQuestionSentenceMap = { + 'three-more': 'People who usually live outside the UK who are staying in the UK for 3 months or more', + 'perm-away': 'People who work away from home within the UK, if this is' + + ' their permanent or family home', + 'armed-forces': 'Members of the armed forces, if this is their permanent or' + + ' family home', + 'less-twelve': 'People who are temporarily outside the UK for less than 12' + + ' months', + 'usually-temp': 'People staying temporarily who usually live in the UK but' + + ' do not have another UK address, for example, relatives, friends', + 'other': 'Other people who usually live here, including anyone temporarily' + + ' away from home' +}; diff --git a/_prototypes/your-household-interview-led/assets/numbers-to-words.js b/_prototypes/your-household-interview-led/assets/numbers-to-words.js new file mode 100644 index 0000000000..f59219fca8 --- /dev/null +++ b/_prototypes/your-household-interview-led/assets/numbers-to-words.js @@ -0,0 +1,146 @@ +/** + * Copied from: + * https://codereview.stackexchange.com/questions/90349/changing-number-to-words-in-javascript + * =============== + */ +var ONE_TO_NINETEEN = [ + 'one', 'two', 'three', 'four', 'five', + 'six', 'seven', 'eight', 'nine', 'ten', + 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', + 'sixteen', 'seventeen', 'eighteen', 'nineteen' +]; + +var TENS = [ + 'ten', 'twenty', 'thirty', 'forty', 'fifty', + 'sixty', 'seventy', 'eighty', 'ninety' +]; + +var SCALES = ['thousand', 'million', 'billion', 'trillion']; + +// helper function for use with Array.filter +function isTruthy(item) { + return !!item; +} + +// convert a number into 'chunks' of 0-999 +function chunk(number) { + var thousands = []; + + while(number > 0) { + thousands.push(number % 1000); + number = Math.floor(number / 1000); + } + + return thousands; +} + +// translate a number from 1-999 into English +function inEnglish(number) { + var thousands, hundreds, tens, ones, words = []; + + if(number < 20) { + return ONE_TO_NINETEEN[number - 1]; // may be undefined + } + + if(number < 100) { + ones = number % 10; + tens = number / 10 | 0; // equivalent to Math.floor(number / 10) + + words.push(TENS[tens - 1]); + words.push(inEnglish(ones)); + + return words.filter(isTruthy).join('-'); + } + + hundreds = number / 100 | 0; + words.push(inEnglish(hundreds)); + words.push('hundred'); + words.push(inEnglish(number % 100)); + + return words.filter(isTruthy).join(' '); +} + +// append the word for a scale. Made for use with Array.map +function appendScale(chunk, exp) { + var scale; + if (!chunk) { + return null; + } + scale = SCALES[exp - 1]; + return [chunk, scale].filter(isTruthy).join(' '); +} + +/** + * =============== + * End copy + */ + +/** + * Modification - decorator + */ +var NUMBER_TO_POSITION_TEXT_MAP = { + 'one': 'first', + 'two': 'second', + 'three': 'third', + 'four': 'fourth', + 'five': 'fifth', + 'six': 'sixth', + 'seven': 'seventh', + 'eight': 'eighth', + 'nine': 'nineth', + 'ten': 'tenth', + 'eleven': 'eleventh', + 'twelve': 'twelveth', + 'thirteen': 'thirteenth', + 'fourteen': 'fourteenth', + 'fifteen': 'fifteenth', + 'sixteen': 'sixteenth', + 'seventeen': 'seventeenth', + 'eighteen': 'eighteenth', + 'nineteen': 'nineteenth', + + 'twenty': 'twentieth', + 'thirty': 'thirtieth', + 'forty': 'fortieth', + 'fifty': 'fiftieth', + 'sixty': 'sixtieth', + 'seventy': 'seventieth', + 'eighty': 'eightieth', + 'ninety': 'ninetieth', + 'hundred': 'hundredth', + + 'thousand': 'thousandth', + 'million': 'millionth', + 'billion': 'billionth', + 'trillion': 'trillionth' +}; + +export function numberToPositionWord(num) { + const str = chunk(num) + .map(inEnglish) + .map(appendScale) + .filter(isTruthy) + .reverse() + .join(' '); + + const sub = str.split(' '), + lastWordDashSplitArr = sub[sub.length - 1].split('-'), + lastWord = lastWordDashSplitArr[lastWordDashSplitArr.length - 1], + + newLastWord = (lastWordDashSplitArr.length > 1? lastWordDashSplitArr[0] + '-' : '') + + NUMBER_TO_POSITION_TEXT_MAP[lastWord]; + + /*console.log('str:', str); + console.log('sub:', sub); + console.log('lastWordDashSplitArr:', lastWordDashSplitArr); + console.log('lastWord:', lastWord); + console.log('newLastWord:', newLastWord);*/ + + const subCopy = [].concat(sub); + subCopy.pop(); + const prefix = subCopy.join(' '); + const result = (prefix ? prefix + ' ' : '') + newLastWord; + + // console.log('result', (prefix ? prefix + ' ' : '') + newLastWord); + return result; +} diff --git a/_prototypes/your-household-interview-led/assets/personal-details.js b/_prototypes/your-household-interview-led/assets/personal-details.js new file mode 100644 index 0000000000..d9c9f4f5a4 --- /dev/null +++ b/_prototypes/your-household-interview-led/assets/personal-details.js @@ -0,0 +1,185 @@ +export const PERSONAL_DETAILS_KEY = 'individual-details'; +export const PERSONAL_PINS_KEY = 'individual-pins'; + +export const personalDetailsMaritalStatusMap = { + 'never': { + description: 'Never married and never registered a same-sex civil' + + ' partnership' + }, + 'married': { + description: 'Married' + }, + 'registered': { + description: 'In a registered same-sex civil partnership' + }, + 'separated-married': { + description: 'Separated, but still legally married' + }, + 'divorced': { + description: 'Divorced' + }, + 'former-partnership': { + description: 'Formerly in a same-sex civil partnership which is now' + + ' legally dissolved' + }, + 'widowed': { + description: 'Widowed' + }, + 'surviving-partner': { + description: 'Surviving partner from a same-sex civil partnership' + }, + 'separated-partnership': { + description: 'Separated, but still legally in a same-sex civil partnership' + } +}; + +export const personalDetailsCountryMap = { + 'england': { + description: 'England' + }, + 'wales': { + description: 'Wales' + }, + 'scotland': { + description: 'Scotland' + }, + 'northern-ireland': { + description: 'Northern Ireland' + }, + 'republic-ireland': { + description: 'Republic of Ireland' + }, + 'elsewhere': { + description: 'Elsewhere' + } +}; + +export const personalDetailsOrientationMap = { + 'straight': { + description: 'Straight or Heterosexual' + }, + 'gay': { + description: 'Gay or Lesbian' + }, + 'bisexual': { + description: 'Bisexual' + }, + 'other': { + description: 'Other' + }, + 'no-say': { + description: 'Prefer not to say' + } +}; + +export function addUpdatePersonalDetailsDOB(personId, day, month, year) { + let allDetails = getAllPersonalDetails(), + details = allDetails[personId] || {}; + + details['dob'] = { + day, + month, + year + }; + + updatePersonalDetails(personId, details); + + return details; +} + +export function addUpdateMaritalStatus(personId, val) { + let allDetails = getAllPersonalDetails(), + details = allDetails[personId] || {}; + + details['maritalStatus'] = val; + + updatePersonalDetails(personId, details); + + return details; +} + +export function addUpdateCountry(personId, val) { + let allDetails = getAllPersonalDetails(), + details = allDetails[personId] || {}; + + details['country'] = val; + + updatePersonalDetails(personId, details); + + return details; +} + +export function addUpdateOrientation(personId, val) { + let allDetails = getAllPersonalDetails(), + details = allDetails[personId] || {}; + + details['orientation'] = val; + + updatePersonalDetails(personId, details); + + return details; +} + +export function addUpdateSalary(personId, val) { + let allDetails = getAllPersonalDetails(), + details = allDetails[personId] || {}; + + details['salary'] = val; + + updatePersonalDetails(personId, details); + + return details; +} + +export function getPins() { + return JSON.parse(sessionStorage.getItem(PERSONAL_PINS_KEY)) || {}; +} + +export function createPinFor(personId, opts = {}) { + let pins = getPins(); + + pins[personId] = { + pin: _.random(10000, 99999), + exported: !!opts.exported + }; + + sessionStorage.setItem(PERSONAL_PINS_KEY, JSON.stringify(pins)); + + return pins[personId]; +} + +export function getPinFor(personId) { + return getPins()[personId]; +} + +export function unsetPinFor(personId) { + let pins = getPins(); + + delete pins[personId]; + + sessionStorage.setItem(PERSONAL_PINS_KEY, JSON.stringify(pins)); +} + +export function updatePersonalDetails(personId, details) { + sessionStorage.setItem(PERSONAL_DETAILS_KEY, JSON.stringify({ + ...getAllPersonalDetails(), + [personId]: details + })); + + return details; +} + +export function getAllPersonalDetails() { + return JSON.parse(sessionStorage.getItem(PERSONAL_DETAILS_KEY)) || {}; +} + +export function getPersonalDetailsFor(personId) { + const storageObj = JSON.parse(sessionStorage.getItem(PERSONAL_DETAILS_KEY)) || {}, + personObj = storageObj[personId]; + + if (!personObj) { + console.log('Personal details for ' + personId + ' not found'); + } + + return personObj; +} diff --git a/_prototypes/your-household-interview-led/assets/prototype-tools.js b/_prototypes/your-household-interview-led/assets/prototype-tools.js new file mode 100644 index 0000000000..f10303505c --- /dev/null +++ b/_prototypes/your-household-interview-led/assets/prototype-tools.js @@ -0,0 +1,140 @@ +export function tools () { + + const $listLinks = $('.test-data-links'), + + $createFamilyHousehold = $('
  • ' + + 'Create family household
  • '), + + $createFamilyRelationships = $('
  • ' + + 'Create family relationships
  • '), + + familyHouseholdMembersData = [{ + 'type': 'household-member', + '@person': { + 'fullName': 'Dave Jones', + 'firstName': 'Dave', + 'middleName': '', + 'lastName': 'Jones', + 'id': 'person_me' + } + }, { + 'type': + 'household-member', + '@person': { + 'fullName': 'Sally Jones', + 'firstName': 'Sally', + 'middleName': '', + 'lastName': 'Jones', + 'id': 'person1' + } + }, { + 'type': 'household-member', + '@person': { + 'fullName': 'Rebecca Jones', + 'firstName': 'Rebecca', + 'middleName': '', + 'lastName': 'Jones', + 'id': 'person2' + } + }, { + 'type': 'household-member', + '@person': { + 'fullName': 'Amy Jones', + 'firstName': 'Amy', + 'middleName': '', + 'lastName': 'Jones', + 'id': 'person3' + } + }], + + familyHouseholdRelationshipsData = [{ + 'personIsDescription': 'husband-wife', + 'personIsId': 'person1', + 'personToId': 'person_me', + 'inferred': false, + 'id': 1 + }, { + 'personIsDescription': 'son-daughter', + 'personIsId': 'person2', + 'personToId': 'person_me', + 'inferred': false, + 'id': 2 + }, { + 'personIsDescription': 'mother-father', + 'personIsId': 'person_me', + 'personToId': 'person3', + 'inferred': false, + 'id': 3 + }, { + 'personIsDescription': 'son-daughter', + 'personIsId': 'person2', + 'personToId': 'person1', + 'inferred': false, + 'id': 4 + }, { + 'personIsDescription': 'mother-father', + 'personIsId': 'person1', + 'personToId': 'person3', + 'inferred': false, + 'id': 5 + }, { + 'personIsDescription': 'brother-sister', + 'personIsId': 'person3', + 'personToId': 'person2', + 'inferred': true, + 'inferredBy': [3, 5, 2, 4], + 'id': 6 + }], + + userData = { + 'fullName': 'Dave Jones', + 'firstName': 'Dave', + 'middleName': '', + 'lastName': 'Jones' + }; + + $createFamilyHousehold.on('click', function(e) { + e.preventDefault(); + clearStorage(); + createFamilyHousehold(); + }); + + $createFamilyRelationships.on('click', function(e) { + e.preventDefault(); + clearStorage(); + createFamilyHousehold(); + createFamilyRelationships(); + }); + + function prerequisites() { + sessionStorage.setItem('address', '12 Somewhere Close, Newport, CF12 3AB'); + sessionStorage.setItem('address-line-1', '12'); + sessionStorage.setItem('address-line-2', 'Somewhere close'); + sessionStorage.setItem('county', 'Newport'); + sessionStorage.setItem('lives-here', 'yes'); + sessionStorage.setItem('postcode', 'CF12 3AB'); + sessionStorage.setItem('town-city', 'Newport'); + } + + function createFamilyHousehold() { + prerequisites(); + sessionStorage.setItem('user-details', JSON.stringify(userData)); + sessionStorage.setItem(window.ONS.storage.KEYS.HOUSEHOLD_MEMBERS_STORAGE_KEY, JSON.stringify(familyHouseholdMembersData)); + sessionStorage.setItem('household-members-increment', JSON.stringify(4)); + window.location.href = '../summary'; + } + + function createFamilyRelationships() { + sessionStorage.setItem(window.ONS.storage.KEYS.RELATIONSHIPS_STORAGE_KEY, JSON.stringify(familyHouseholdRelationshipsData)); + sessionStorage.setItem('relationships-increment', JSON.stringify(6)); + window.location.href = '../relationships-summary'; + } + + function clearStorage() { + sessionStorage.clear(); + } + + $listLinks.append($createFamilyHousehold); + $listLinks.append($createFamilyRelationships); +} diff --git a/_prototypes/your-household-interview-led/assets/relationships.js b/_prototypes/your-household-interview-led/assets/relationships.js new file mode 100644 index 0000000000..37472d7412 --- /dev/null +++ b/_prototypes/your-household-interview-led/assets/relationships.js @@ -0,0 +1,619 @@ +import {autoIncrementId, removeFromList, trailingNameS} from './utils'; +import { + isHouseholdMember, + getAllHouseholdMembers, + getHouseholdMemberByPersonId, + USER_HOUSEHOLD_MEMBER_ID +} from './household'; + +/** + * Augment Underscore library + */ +const _ = window._ || {}; + +export const RELATIONSHIPS_STORAGE_KEY = 'relationships'; + +export const relationshipTypes = { + 'spouse': {id: 'spouse'}, + 'child-parent': {id: 'child-parent'}, + 'step-child-parent': {id: 'step-child-parent'}, + 'grandchild-grandparent': {id: 'grandchild-grandparent'}, + 'half-sibling': {id: 'half-sibling'}, + 'sibling': {id: 'sibling'}, + 'step-brother-sister': {id: 'step-brother-sister'}, + 'partner': {id: 'partner'}, + 'unrelated': {id: 'unrelated'}, + 'other-relation': {id: 'other-relation'} +}; + +export const relationshipDescriptionMap = { + // covered + 'husband-wife': { + sentanceLabel: 'husband or wife', + summaryAdjective: 'husband or wife', + type: relationshipTypes['spouse'] + }, + // covered + 'mother-father': { + sentanceLabel: 'mother or father', + summaryAdjective: 'mother or father', + type: relationshipTypes['child-parent'] + }, + // covered + 'step-mother-father': { + sentanceLabel: 'stepmother or stepfather', + summaryAdjective: 'stepmother or stepfather', + type: relationshipTypes['step-child-parent'] + }, + // covered + 'son-daughter': { + sentanceLabel: 'son or daughter', + summaryAdjective: 'son or daughter', + type: relationshipTypes['child-parent'] + }, + // covered + 'half-brother-sister': { + sentanceLabel: 'half-brother or half-sister', + summaryAdjective: 'half-brother or half-sister', + type: relationshipTypes['half-sibling'] + }, + // covered + 'step-child': { + sentanceLabel: 'stepchild', + summaryAdjective: 'stepchild', + type: relationshipTypes['step-child-parent'] + }, + // covered + 'grandparent': { + sentanceLabel: 'grandparent', + summaryAdjective: 'grandparent', + type: relationshipTypes['grandchild-grandparent'] + }, + // covered + 'grandchild': { + sentanceLabel: 'grandchild', + summaryAdjective: 'grandchild', + type: relationshipTypes['grandchild-grandparent'] + }, + // covered + 'brother-sister': { + sentanceLabel: 'brother or sister', + summaryAdjective: 'brother or sister', + type: relationshipTypes['sibling'] + }, + // covered + 'step-brother-sister': { + sentanceLabel: 'stepbrother or stepsister', + summaryAdjective: 'stepbrother or stepsister', + type: relationshipTypes['step-brother-sister'] + }, + // covered + 'other-relation': { + sentanceLabel: 'other relation', + summaryAdjective: 'related', + type: relationshipTypes['other-relation'] + }, + // covered + 'partner': { + sentanceLabel: 'partner', + summaryAdjective: 'partner', + type: relationshipTypes['partner'] + }, + 'same-sex-partner': { + sentanceLabel: 'legally registered civil partner', + summaryAdjective: 'legally registered civil partner', + type: relationshipTypes['partner'] + }, + // covered + 'unrelated': { + sentanceLabel: 'unrelated', + summaryAdjective: 'unrelated', + type: relationshipTypes['unrelated'] + } +}; + +function nameElement(name) { + return '' + name + ''; +} + +function personListStr(peopleArr, opts = {}) { + if (peopleArr.length < 1) { + console.log(peopleArr, 'not enough people to create a list string'); + return; + } + + if (peopleArr.length === 1) { + return nameElement(peopleArr[0].fullName + formatPersonIfYou(peopleArr[0])); + } + + let peopleCopy = [...peopleArr], + lastPerson = peopleCopy.pop(); + + return peopleCopy + .map((person) => `${nameElement(person.fullName + + (opts.isFamily ? trailingNameS(person.fullName) : '') + + formatPersonIfYou(person))}`) + .join(', ') + ' and ' + nameElement(lastPerson.fullName + + (opts.isFamily ? trailingNameS(lastPerson.fullName) : '') + + formatPersonIfYou(lastPerson)) +} + +function formatPersonIfYou(person) { + return person.id === USER_HOUSEHOLD_MEMBER_ID ? ' (You)' : ''; +} + +export const relationshipSummaryTemplates = { + 'partnership': (person1, person2, description) => { + return `${nameElement(person1.fullName + formatPersonIfYou(person1))} is ${nameElement(person2.fullName + trailingNameS(person2.fullName) + formatPersonIfYou(person2))} ${description}`; + }, + 'twoFamilyMembersToMany': (parent1, parent2, childrenArr, description) => { + return `${nameElement(parent1.fullName + formatPersonIfYou(parent1))} and ${nameElement(parent2.fullName + formatPersonIfYou(parent2))} are ${personListStr(childrenArr, {isFamily: true})} ${description}`; + }, + 'oneFamilyMemberToMany': (parent, childrenArr, description) => { + console.log(parent, childrenArr, description); + return `${nameElement(parent.fullName + formatPersonIfYou(parent))} is ${personListStr(childrenArr, {isFamily: true})} ${description}`; + }, + 'manyToMany': (peopleArr1, peopleArr2, description) => { + return `${personListStr(peopleArr1)} ${peopleArr1.length > 1 ? 'are' : 'is'} ${description} to ${personListStr(peopleArr2)}`; + }, + 'allMutual': (peopleArr, description) => { + return `${personListStr(peopleArr)} are ${description}`; + } +}; + +/** + * Types + */ +export function relationship(description, personIsId, personToId, opts = {}) { + return { + personIsDescription: description, + personIsId: personIsId, + personToId: personToId, + inferred: !!opts.inferred, + inferredBy: opts.inferredBy + }; +} + +/** + * Storage + */ +export function addRelationship(relationshipObj) { + let householdRelationships = getAllRelationships() || [], + item = { + ...relationshipObj, + id: autoIncrementId(RELATIONSHIPS_STORAGE_KEY) + }; + + householdRelationships.push(item); + + sessionStorage.setItem(RELATIONSHIPS_STORAGE_KEY, + JSON.stringify(householdRelationships)); + + return item; +} + +export function deleteRelationship(relationshipObj) { + let householdRelationships = (getAllRelationships() || []) + .filter(relationship => relationship.id !== relationshipObj.id); + + sessionStorage.setItem(RELATIONSHIPS_STORAGE_KEY, + JSON.stringify(householdRelationships)); +} + +export function editRelationship(relationshipId, valueObject) { + let householdRelationships = (getAllRelationships() || []).map(function(relationship) { + return (relationship.id + '') === (relationshipId + '') ? { + ...valueObject, + id: relationshipId + } : relationship; + }); + + sessionStorage.setItem(RELATIONSHIPS_STORAGE_KEY, + JSON.stringify(householdRelationships)); +} + +export function getAllRelationships() { + return JSON.parse(sessionStorage.getItem(RELATIONSHIPS_STORAGE_KEY)) || []; +} + +export function getAllManualRelationships() { + return getAllRelationships().filter((relationship) => { + return !relationship.inferred; + }); +} + +export function deleteAllRelationshipsForMember(personId) { + const householdRelationships = getAllRelationships() + .filter((relationship) => { + return !(personId === relationship.personIsId || personId === relationship.personToId); + }); + + sessionStorage.setItem(RELATIONSHIPS_STORAGE_KEY, + JSON.stringify(householdRelationships)); +} + +/** + * Comparators + */ +export function isInRelationship(personId, relationship) { + return relationship.personToId === personId || relationship.personIsId === personId; +} + +export function isAChildInRelationship(personId, relationship) { + /** + * Guard + */ + if (!isInRelationship(personId, relationship)) { + return false; + } + + return ( + relationship.personIsDescription === 'mother-father' && + relationship.personToId === personId + ) || ( + relationship.personIsDescription === 'son-daughter' && + relationship.personIsId === personId + ); +} + +export function isASiblingInRelationship(personId, relationship) { + return isInRelationship(personId, relationship) && + relationshipDescriptionMap[relationship.personIsDescription].type.id === 'sibling'; +} + +export function isAParentInRelationship(personId, relationship) { + /** + * Guard + */ + if (!isInRelationship(personId, relationship)) { + return false; + } + + return ( + relationship.personIsDescription === 'mother-father' && + relationship.personIsId === personId + ) || ( + relationship.personIsDescription === 'son-daughter' && + relationship.personToId === personId + ); +} + +export function areAnyChildrenInRelationshipNotParent(childrenIds, notParentId, relationship) { + /** + * Guard + * If relationship type is not child-parent + */ + if (relationshipDescriptionMap[relationship.personIsDescription] + .type.id !== 'child-parent') { + + return false; + } + + let childIndexAsPersonIs = childrenIds.indexOf(relationship.personIsId), + childIndexAsPersonTo = childrenIds.indexOf(relationship.personToId); + + /** + * Find parents with the same children + * + * If a personIs-child is not in relationship + * or 2 children are found in relationship + */ + if ( + (childIndexAsPersonIs === -1 && childIndexAsPersonTo === -1) || + (childIndexAsPersonIs !== -1 && childIndexAsPersonTo !== -1) + ) { + return false; + } + + /** + * Child must be in relationship, get child index + */ + let childIndex = childIndexAsPersonIs !== -1 + ? childIndexAsPersonIs + : childIndexAsPersonTo; + + /** + * If personIs is not in relationship + * and child from previous relationship is a child in this relationship + */ + return !isInRelationship(notParentId, relationship) && + isAChildInRelationship(childrenIds[childIndex], relationship); +} + +export function isRelationshipType(relationshipType, relationship) { + const typeOfRelationship = relationshipDescriptionMap[relationship.personIsDescription] + .type.id; + + /** + * relationshipType can be an array of types + */ + return _.isArray(relationshipType) + ? !!_.find(relationshipType, function(rType) { + return rType === typeOfRelationship; + }) + : typeOfRelationship === relationshipType; +} + +export function isRelationshipInferred(relationship) { + return relationship.inferred; +} + +/** + * Retrieve people by role in relationships + */ +export function getParentIdFromRelationship(relationship) { + let parentId; + + if (relationship.personIsDescription === 'mother-father') { + parentId = relationship.personIsId; + } + + if (relationship.personIsDescription === 'son-daughter') { + parentId = relationship.personToId; + } + + if (!parentId) { + console.log('Parent not found in relationship: ', relationship); + return false; + } + + return parentId; +} + +export function getChildIdFromRelationship(relationship) { + let childId; + + if (relationship.personIsDescription === 'mother-father') { + childId = relationship.personToId; + } + + if (relationship.personIsDescription === 'son-daughter') { + childId = relationship.personIsId; + } + + if (!childId) { + console.log('Child not found in relationship: ', relationship); + return false; + } + + return childId; +} + +export function getSiblingIdFromRelationship(personId, relationship) { + if (!isInRelationship(personId, relationship)) { + console.log('Person ' + personId + ' not found in relationship: ', relationship); + return false; + } + + return relationship[relationship.personIsId === personId ? 'personToId' : 'personIsId']; +} + +export function getOtherPersonIdFromRelationship(personId, relationship) { + return relationship.personIsId === personId + ? relationship.personToId : relationship.personIsId; +} + +export function getAllParentsOf(personId) { + return getAllRelationships() + .filter(isAChildInRelationship.bind(null, personId)) + .map(relationship => getPersonFromMember(getHouseholdMemberByPersonId(getParentIdFromRelationship(relationship)))); +} + +export function getAllChildrenOf(personId) { + return getAllRelationships() + .filter(isAParentInRelationship.bind(null, personId)) + .map(relationship => getHouseholdMemberByPersonId(getChildIdFromRelationship(relationship))['@person']); +} + +export function getPersonIdFromPerson(person) { + return person.id; +} + +export function getPersonFromMember(member) { + return member['@person']; +} + +/** + * Missing relationship inference + */ +export const missingRelationshipInference = { + siblingsOf(subjectMember) { + + const missingRelationships = [], + allRelationships = getAllRelationships(), + person = getPersonFromMember(subjectMember), + personId = person.id, + + parents = getAllParentsOf(personId), + + siblingIds = allRelationships + .filter(isASiblingInRelationship.bind(null, personId)) + .map(getSiblingIdFromRelationship.bind(null, personId)); + + /** + * If 2 parent relationships of 'person' are found we can attempt to infer + * sibling relationships + */ + if (parents.length === 2) { + + getAllHouseholdMembers() + .filter(isHouseholdMember) + .forEach((member) => { + + const memberPersonId = member['@person'].id; + + /** + * Guard + * If member is the subject member + * or member is a parent + * or member already has a sibling relationship with 'person' + * skip member + */ + if (memberPersonId === personId || + memberPersonId === parents[0].id || memberPersonId === parents[1].id || + siblingIds.indexOf(memberPersonId) > -1) { + return; + } + + const memberParents = getAllParentsOf(memberPersonId); + + /** + * If 2 parents of 'member' are found + * and they are the same parents of 'person' + * we have identified a missing inferred relationship + */ + if (memberParents.length === 2 && + _.difference( + parents.map(getPersonIdFromPerson), + memberParents.map(getPersonIdFromPerson) + ).length === 0) { + + /** + * Add to missingRelationships + */ + missingRelationships.push(relationship( + 'brother-sister', + personId, + memberPersonId, + { + inferred: true, + inferredBy: [ + /** + * Must be 4 relationships + * Could have used member's parents but we can assume they + * must be the same at this point or the inferrence + * couldn't happen. + */ + getRelationshipOf(personId, parents[0].id).id, + getRelationshipOf(personId, parents[1].id).id, + getRelationshipOf(memberPersonId, parents[0].id).id, + getRelationshipOf(memberPersonId, parents[1].id).id + ] + } + )); + } + }); + } + + return missingRelationships; + } +}; + +export function inferRelationships(relationship, personIs, personTo) { + var missingRelationships = []; + + if (relationship.personIsDescription === 'mother-father') { + missingRelationships = missingRelationships.concat( + missingRelationshipInference.siblingsOf(personTo) + ); + } + + if (relationship.personIsDescription === 'son-daughter') { + missingRelationships = missingRelationships.concat( + missingRelationshipInference.siblingsOf(personIs) + ); + } + + $.each(missingRelationships, function(i, relationship) { + addRelationship(relationship); + }); +} + +export function findNextMissingRelationship() { + let householdMembers = getAllHouseholdMembers().filter(isHouseholdMember), + relationships = getAllRelationships(), + missingRelationshipMembers = [], + personIs = null; + + /** + * Find the next missing relationship + */ + $.each(householdMembers, function(i, member) { + const personId = member['@person'].id; + + /** + * Get all relationships for this member + */ + const memberRelationships = relationships.filter(function(relationship) { + return relationship.personIsId === personId || relationship.personToId === personId; + }), + + memberRelationshipToIds = memberRelationships.map(function(relationship) { + return relationship.personIsId === personId ? relationship.personToId : relationship.personIsId; + }) || []; + + /** + * If total relationships related to this member isn't equal to + * total household members -1, indicates missing relationship + */ + if (memberRelationships.length < householdMembers.length - 1) { + + /** + * All missing relationship members + */ + missingRelationshipMembers = householdMembers.filter(function(m) { + return memberRelationshipToIds.indexOf(m['@person'].id) === -1 && + m['@person'].id !== personId; + }); + + personIs = member; + + return false; + } + }); + + return personIs ? { + personIs: personIs, + personTo: missingRelationshipMembers[0] + } : null; +} + +export function getPeopleIdsMissingRelationshipsWithPerson(personId) { + const remainingPersonIds = getAllHouseholdMembers() + .filter(isHouseholdMember) + .map(function(member) { + return member['@person'].id; + }); + + /** + * Remove this person from the list + */ + removeFromList(remainingPersonIds, personId); + + $.each(getAllRelationships(), function(i, relationship) { + if (!isInRelationship(personId, relationship)) { + return; + } + + /** + * Remove the other person from the remainingPersonIds list + */ + removeFromList( + remainingPersonIds, + getOtherPersonIdFromRelationship(personId, relationship) + ); + }); + + return remainingPersonIds; +} + +export function getRelationshipType(relationship) { + return relationshipDescriptionMap[relationship.personIsDescription].type; +} + +/** + * Retrieve from relationship group + */ +export function getRelationshipsWithPersonIds(relationships, idArr) { + return relationships.filter(function(childRelationship) { + return idArr.indexOf(childRelationship.personIsId) !== -1 || + idArr.indexOf(childRelationship.personToId) !== -1; + }); +} + +export function getRelationshipOf(person1, person2) { + return getAllRelationships().find(function(relationship) { + return isInRelationship(person1, relationship) && + isInRelationship(person2, relationship); + }); +} diff --git a/_prototypes/your-household-interview-led/assets/utils.js b/_prototypes/your-household-interview-led/assets/utils.js new file mode 100644 index 0000000000..c0898a3d80 --- /dev/null +++ b/_prototypes/your-household-interview-led/assets/utils.js @@ -0,0 +1,39 @@ +export function autoIncrementId(collection) { + let k = collection + '-increment', + id = parseInt(sessionStorage.getItem(k)) || 0; + + id++; + + sessionStorage.setItem(k, JSON.stringify(id)); + + return id; +} + +export function removeFromList(list, val) { + + function doRemove(item) { + var foundId = list.indexOf(item); + + /** + * Guard + */ + if (foundId === -1) { + console.log('Attempt to remove from list failed: ', list, val); + return; + } + + list.splice(foundId, 1); + } + + if (_.isArray(val)) { + $.each(val, function(i, item) { + doRemove(item); + }); + } else { + doRemove(val); + } +} + +export function trailingNameS(name) { + return name[name.length - 1] === 's' ? '\’' : '\’s'; +} diff --git a/_prototypes/your-household-interview-led/bundle.js b/_prototypes/your-household-interview-led/bundle.js new file mode 100644 index 0000000000..a4ff5c0402 --- /dev/null +++ b/_prototypes/your-household-interview-led/bundle.js @@ -0,0 +1,406 @@ +import { + RELATIONSHIPS_STORAGE_KEY, + relationshipDescriptionMap, + addRelationship, + deleteRelationship, + editRelationship, + getAllRelationships, + getAllManualRelationships, + deleteAllRelationshipsForMember, + relationshipSummaryTemplates, + missingRelationshipInference, + inferRelationships, + getAllParentsOf, + getAllChildrenOf, + getParentIdFromRelationship, + getChildIdFromRelationship, + getOtherPersonIdFromRelationship, + isAChildInRelationship, + isAParentInRelationship, + isInRelationship, + areAnyChildrenInRelationshipNotParent, + isRelationshipType, + isRelationshipInferred, + getRelationshipOf, + getRelationshipsWithPersonIds, + getPeopleIdsMissingRelationshipsWithPerson, + getRelationshipType, + findNextMissingRelationship, + relationship +} from './assets/relationships'; +import { + HOUSEHOLD_MEMBER_TYPE, + VISITOR_TYPE, + USER_HOUSEHOLD_MEMBER_ID, + HOUSEHOLD_MEMBERS_STORAGE_KEY, + addHouseholdMember, + updateHouseholdMember, + deleteHouseholdMember, + getAllHouseholdMembers, + getUserAsHouseholdMember, + getHouseholdMemberByPersonId, + getMemberPersonId, + updateUserAsHouseholdMember, + deleteUserAsHouseholdMember, + isVisitor, + isOtherHouseholdMember, + isHouseholdMember, + person, + tempAwayQuestionSentenceMap +} from './assets/household'; +import { + addUpdatePersonalDetailsDOB, + getPersonalDetailsFor, + addUpdateMaritalStatus, + addUpdateCountry, + addUpdateOrientation, + addUpdateSalary, + + personalDetailsMaritalStatusMap, + personalDetailsCountryMap, + personalDetailsOrientationMap, + + createPinFor, + getPinFor, + unsetPinFor +} from './assets/personal-details'; +import {removeFromList, trailingNameS} from './assets/utils'; + +import { numberToPositionWord } from './assets/numbers-to-words'; + +import { tools } from './assets/prototype-tools'; + +export const USER_STORAGE_KEY = 'user-details'; +export const INDIVIDUAL_PROXY_STORAGE_KEY = 'proxy-person'; + +export function getAddress() { + let addressLines = sessionStorage.getItem('address').split(','); + + return { + addressLine1: addressLines[0], + addressLine2: addressLines[1], + addressLine3: addressLines[2], + addressCounty: addressLines[4], + addressTownCity: addressLines[3], + addressPostcode: addressLines[5] + } +} + +/** + * User + */ +export function addUserPerson(person) { + sessionStorage.setItem(USER_STORAGE_KEY, JSON.stringify(person)); +} + +export function getUserPerson() { + return JSON.parse(sessionStorage.getItem(USER_STORAGE_KEY)); +} + +/** + * Helpers + */ +function createNavItem(member) { + let $nodeEl = $(''), + $linkEl = $nodeEl.find('.js-template-nav-item-label'); + + $linkEl.html(member['@person'].fullName); + + if (member['@person'].id === USER_HOUSEHOLD_MEMBER_ID) { + $linkEl.attr('href', '../what-is-your-name'); + } else { + $linkEl.attr('href', '../who-else-to-add?edit=' + member['@person'].id); + } + + return $nodeEl; +} + +function updateHouseholdVisitorsNavigationItems() { + let allHouseholdMembers = window.ONS.storage.getAllHouseholdMembers(), + householdMembers = allHouseholdMembers.filter(window.ONS.storage.isHouseholdMember), + visitors = allHouseholdMembers.filter(window.ONS.storage.isVisitor); + + const $navigationHouseholdMembersEl = $('#navigation-household-members'), + $navigationVisitorsEl = $('#navigation-visitors'); + + if (householdMembers.length) { + $.each(householdMembers, function(i, member) { + $navigationHouseholdMembersEl.append(createNavItem(member)); + }); + } else { + $navigationHouseholdMembersEl.parent().hide(); + } + + if (visitors.length) { + $.each(visitors, function(i, member) { + $navigationVisitorsEl.append(createNavItem(member)); + }); + } else { + $navigationVisitorsEl.parent().hide(); + } +} + +function createListItemPerson(member) { + return $('
  • ').addClass('mars').html( + '' + + member['@person'].fullName + + (member['@person'].id === USER_HOUSEHOLD_MEMBER_ID ? ' (You)' : '') + + '' + ); +} + +function populateList($el, memberType) { + if (!$el.length) { + return; + } + + let members = getAllHouseholdMembers() || []; + + $el.empty().append(members.filter((member) => { + return member.type === memberType; + }).map(createListItemPerson)); + + $el.addClass('list list--people-plain'); +} + +function populateHouseholdList() { + populateList($('#household-members'), HOUSEHOLD_MEMBER_TYPE); +} + +function populateVisitorList() { + populateList($('#visitors-list'), VISITOR_TYPE); +} + +function updateAddresses() { + let addressLines = (sessionStorage.getItem('address') || '').split(','), + addressLine1 = addressLines[0], + addressLine2 = addressLines[1]; + + $('#section-address').html(addressLine1 || 'Address not' + + ' found'); + $('.address-text').html( + addressLine1 && addressLine2 + ? ( + addressLine1 + (addressLine2 ? ', ' + addressLine2 : '') + ) + : 'Address not found' + ); + + $('.address-text-line1').html(addressLine1); + + let personId = new URLSearchParams(window.location.search).get('person'), + person; + + if (personId) { + person = getHouseholdMemberByPersonId(personId)['@person']; + $('#section-individual').html(person.fullName); + + $('.js-person-fullname-from-url-id').html(person.fullName); + } +} + +const secureLinkTextMap = { + 'question-you': { + description: 'Want to keep your answers secure from other people at this' + + ' address?', + linkText: 'Get a separate access code to submit an individual response', + link: '../individual-decision-secure' + }, + 'pin-you': { + description: 'You\'ve chosen to keep your answers secure', + linkText: 'Cancel this and make answers available to the rest of the' + + ' household', + link: '../individual-decision-secure' + }, + 'question-proxy': { + description: 'Not happy to continue answering for $[NAME]?', + linkText: 'Request an individual access code to be sent to them', + link: '../individual-decision-other-secure' + } +}; + +function updateAllPreviousLinks() { + $('.js-previous-link').attr('href', document.referrer); +} + +function updatePersonLink() { + const personId = new URLSearchParams(window.location.search).get('person'); + + if (personId) { + let urlParam = new URLSearchParams(window.location.search), + person = getHouseholdMemberByPersonId(personId)['@person'], + pinObj = getPinFor(personId), + secureLinkTextConfig = secureLinkTextMap[ + (getAnsweringIndividualByProxy() ? 'question-proxy' : (pinObj && pinObj.pin ? 'pin-you' : 'question-you')) + ], + linkHref = secureLinkTextConfig.link + '?person=' + personId + + '&returnurl=' + window.location.pathname, + surveyType = urlParam.get('survey'); + + linkHref += (surveyType ? '&survey=' + surveyType : ''); + + let $secureLink = $('.js-link-secure'); + $secureLink.attr('href', linkHref); + + $secureLink.html(secureLinkTextConfig.linkText); + $('.js-link-secure-label').html(secureLinkTextConfig.description.replace('$[NAME]', person.fullName)); + + let personLink = $('.js-link-person'); + personLink.attr('href', personLink.attr('href') + '?person=' + personId + + (surveyType ? '&survey=' + surveyType : '')); + } +} + +function updateBySurveyType() { + const urlParams = new URLSearchParams(window.location.search), + surveyType = urlParams.get('survey'); + + if (surveyType) { + $('.js-header-title').html(surveyTypeConfig[surveyType].title); + $('#people-living-here').html(surveyTypeConfig[surveyType].householdSectionTitle); + $('#people-living-here').attr('href', surveyTypeConfig[surveyType].householdSectionLink); + $('#relationships-section').attr('href', surveyTypeConfig[surveyType].relationshipsSection); + $('title').html(surveyTypeConfig[surveyType].title); + } +} + +function setAnsweringIndividualByProxy(bool) { + sessionStorage.setItem(INDIVIDUAL_PROXY_STORAGE_KEY, JSON.stringify(bool)); +} + +function getAnsweringIndividualByProxy() { + return JSON.parse(sessionStorage.getItem(INDIVIDUAL_PROXY_STORAGE_KEY)); +} + +const surveyTypeConfig = { + lms: { + title: 'Online Household Study', + householdSectionTitle: 'About your household', + householdSectionLink: '../summary/?survey=lms', + relationshipsSection: '../relationships/?survey=lms' + } +}; + +function doILiveHere() { + return sessionStorage.getItem('lives-here') === 'yes'; +} + +function getSignificant() { + return 'Sunday 13 October 2019'; +} + +function updateSignificantDate() { + $('.js-significant-date').html(getSignificant()); +} + +window.ONS = window.ONS || {}; +window.ONS.storage = { + getAddress, + addHouseholdMember, + updateHouseholdMember, + deleteHouseholdMember, + getAllHouseholdMembers, + addUserPerson, + getUserPerson, + getUserAsHouseholdMember, + getHouseholdMemberByPersonId, + getMemberPersonId, + updateUserAsHouseholdMember, + deleteUserAsHouseholdMember, + tempAwayQuestionSentenceMap, + + isVisitor, + isOtherHouseholdMember, + isHouseholdMember, + + addRelationship, + deleteRelationship, + editRelationship, + getAllRelationships, + getAllManualRelationships, + deleteAllRelationshipsForMember, + + getAllParentsOf, + getAllChildrenOf, + getParentIdFromRelationship, + getChildIdFromRelationship, + getOtherPersonIdFromRelationship, + isAParentInRelationship, + isAChildInRelationship, + isInRelationship, + areAnyChildrenInRelationshipNotParent, + isRelationshipType, + isRelationshipInferred, + getRelationshipOf, + + relationshipDescriptionMap, + relationshipSummaryTemplates, + missingRelationshipInference, + inferRelationships, + getRelationshipsWithPersonIds, + getPeopleIdsMissingRelationshipsWithPerson, + getRelationshipType, + findNextMissingRelationship, + + addUpdatePersonalDetailsDOB, + getPersonalDetailsFor, + addUpdateMaritalStatus, + addUpdateCountry, + addUpdateOrientation, + addUpdateSalary, + + personalDetailsMaritalStatusMap, + personalDetailsCountryMap, + personalDetailsOrientationMap, + + createPinFor, + getPinFor, + unsetPinFor, + + setAnsweringIndividualByProxy, + getAnsweringIndividualByProxy, + + doILiveHere, + + KEYS: { + HOUSEHOLD_MEMBERS_STORAGE_KEY, + USER_STORAGE_KEY, + INDIVIDUAL_PROXY_STORAGE_KEY, + HOUSEHOLD_MEMBER_TYPE, + VISITOR_TYPE, + RELATIONSHIPS_STORAGE_KEY + }, + + IDS: { + USER_HOUSEHOLD_MEMBER_ID + }, + + TYPES: { + person, + relationship + } +}; + +window.ONS.helpers = { + populateHouseholdList, + populateVisitorList +}; + +window.ONS.utils = { + removeFromList, + trailingNameS, + numberToPositionWord +}; + +$(populateHouseholdList); +$(populateVisitorList); +$(updateHouseholdVisitorsNavigationItems); +$(updateAddresses); +$(updatePersonLink); +$(tools); +$(updateAllPreviousLinks); +$(updateBySurveyType); +$(updateSignificantDate); diff --git a/_prototypes/your-household-interview-led/confirm-address.html b/_prototypes/your-household-interview-led/confirm-address.html new file mode 100644 index 0000000000..1e69a213c4 --- /dev/null +++ b/_prototypes/your-household-interview-led/confirm-address.html @@ -0,0 +1,97 @@ +--- +title: Census Coverage Survey +project: your-household +globalcss: false +layout: eq-default-extras +cdn: v1.8.4 +hideSaveLater: true +footer: minimal +--- + + +
    +
    + Previous +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    + Can you confirm this address is correct? +

    +
    + +

    Address not + set

    + +
    +
    +
    +
    + + +
    + +
    + + +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + +
    + + + + + + + diff --git a/_prototypes/your-household-interview-led/do-you-live-here.html b/_prototypes/your-household-interview-led/do-you-live-here.html new file mode 100644 index 0000000000..19c7190b01 --- /dev/null +++ b/_prototypes/your-household-interview-led/do-you-live-here.html @@ -0,0 +1,137 @@ +--- +title: Census Coverage Survey +project: your-household +globalcss: false +layout: eq-default-extras +cdn: v1.8.4 +hideSaveLater: true +footer: minimal +--- + + +
    + +
    + +
    +
    +
    + {% include navigation.html + title="Your household" + items=site.data.your-household-interview-led.navigationItemsHousehold + %} +
    +
    +
    +
    +
    +
    +
    +
    +

    + Were you, or anybody in your current + household usually living at + on + ? +

    + +
    +
    +
    +
    + + +
    + +
    + + +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + + + + + + + + diff --git a/_prototypes/your-household-interview-led/index.html b/_prototypes/your-household-interview-led/index.html new file mode 100644 index 0000000000..b01119c2e5 --- /dev/null +++ b/_prototypes/your-household-interview-led/index.html @@ -0,0 +1,96 @@ +--- +title: Census Coverage Survey +project: your-household +globalcss: false +layout: eq-default-extras +cdn: v1.8.4 +hideSaveLater: true +footer: minimal +--- + + +
    +
    + +
    +
    +
    +
    + +
    +
    + + +
    +
    +
    +

    + Hello my name is Paul Sissons from the Office + for National Statistics. +

    + +

    I delivered a card to say we are carrying out + a Census Coverage Survey in your area. Could you + please spare a little time for a short + interview?

    + +
    + + + +

    Why do I have to include my visitors?

    + +
    +
    +

    Lorem ipsum...

    +
    + +
    +
    +
    +
    +
    + + +
    +
    +
    +
    + + + + + diff --git a/_prototypes/your-household-interview-led/number-of-people.html b/_prototypes/your-household-interview-led/number-of-people.html new file mode 100644 index 0000000000..75d233b69b --- /dev/null +++ b/_prototypes/your-household-interview-led/number-of-people.html @@ -0,0 +1,109 @@ +--- +title: Census Coverage Survey +project: your-household +globalcss: false +layout: eq-default-extras +cdn: v1.8.4 +hideSaveLater: true +footer: minimal +--- + + +
    + +
    + +
    +
    +
    + {% include navigation.html + title="Your household" + items=site.data.your-household-interview-led.navigationItemsHousehold + %} +
    +
    +
    +
    +
    +
    +
    +
    + +

    + 2 + Turn to card 2 to see who + to include +

    +

    + How many people usually lived at + on + ? +

    + +
    +
    + Include +
      +
    • Partners
    • +
    • Children
    • +
    • Babies born on or + before
    • +
    • Housemates
    • +
    • Tenants and lodgers
    • +
    • Students and + schoolchildren who live away + from home during term time
    • +
    + + Exclude +
      +
    • People who have moved + in after
    • +
    +
    +
    + +
    +
    + + +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    + + + + + diff --git a/_prototypes/your-household-interview-led/section-intro.html b/_prototypes/your-household-interview-led/section-intro.html new file mode 100644 index 0000000000..008b233a1a --- /dev/null +++ b/_prototypes/your-household-interview-led/section-intro.html @@ -0,0 +1,79 @@ +--- +title: Census Coverage Survey +project: your-household +globalcss: false +layout: eq-default-extras +cdn: v1.8.4 +hideSaveLater: true +footer: minimal +--- + + +
    + +
    + +
    +
    +
    + {% include navigation.html + title="Your household" + items=site.data.your-household-interview-led.navigationItemsHousehold + %} +
    +
    +
    +
    +
    +
    +

    + People in your household +

    + +

    In this section, we're going to + ask you about the people in this household + on

    + +

    Here are some cards to help with + answering the questions.

    + +

    1 + Turn to card for 1 for the definition of a + household (not necessarily related) living at + the same address who share cooking facilities + and share a living room OR sitting room OR + dining area. +

    +
    +
    +
    + + +
    +
    +
    +
    + + + + + + + diff --git a/_prototypes/your-household-interview-led/style.css b/_prototypes/your-household-interview-led/style.css new file mode 100644 index 0000000000..bf1e622d90 --- /dev/null +++ b/_prototypes/your-household-interview-led/style.css @@ -0,0 +1,80 @@ +.list.list--people-plain { + margin-bottom : 1rem; + list-style-type : none; +} + +.list.list--people-plain .list__item { + background: url(/img/icons/person.svg) 0 .2rem no-repeat; +} + +.list.list--people-plain .list__item-name { + padding-left: 1.5rem; +} + +.list.list--people-plain .list__item-actions { + margin-top: -4px; +} + +.list.list--people-plain .list__item-action + .list__item-action { + margin-left : .5rem; +} + +.modal { + position: fixed; + z-index: 1000; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + justify-content: center; + align-items: center; +} + +.modal__window { + position: relative; + background-color: white; + max-width: 520px; + padding: 2rem; + text-align: center; +} + +/** + * Pattern library fix + */ +.header { + margin-bottom : 0; +} + +.lock { + padding-left : 1.5rem; + background : url('../img/icons/lockicon.svg') no-repeat left top; +} + +.footer { + margin-top : 7rem; +} + +.btn--danger { + background-color : #D0021B; + border-color : #D0021B; +} + +.btn--danger:hover { + background-color : #b00015; + border-color : #b00015; +} + +.card-number { + display : inline-block; + margin-right : .6rem; + padding : .2rem .5rem; + border : 1px solid #999; + border-radius : 2px; +} + +.input--w-7 { + width: 100%; + max-width: calc(8.2195rem + 4px); +} diff --git a/_prototypes/your-household-interview-led/test-address.html b/_prototypes/your-household-interview-led/test-address.html new file mode 100644 index 0000000000..3384e9c3f7 --- /dev/null +++ b/_prototypes/your-household-interview-led/test-address.html @@ -0,0 +1,229 @@ +--- +title: Census Coverage Survey +project: your-household +globalcss: false +layout: eq-default-extras +cdn: v1.8.4 +hideSaveLater: true +footer: minimal +--- + + + + +
    +
    + +
    +
    +
    +
    + +
    +
    + + +
    +
    +
    +

    + What is your address? +

    + +
    + + What is your address? + + +
    +
    +
    +
    +
    + + + + +
    +
    +
    +
    + +
    +
    +
    +
    + + + +
    +
    +
    +
    + +
    +
    +
    +
    + + + +
    +
    +
    +
    + +
    +
    +
    +
    + + + +
    +
    +
    +
    +
    +
    +
    +
    +
    + + +
    +
    +
    +
    + + + + + diff --git a/_prototypes/your-household-interview-led/what-is-your-name.html b/_prototypes/your-household-interview-led/what-is-your-name.html new file mode 100644 index 0000000000..e89070d0e3 --- /dev/null +++ b/_prototypes/your-household-interview-led/what-is-your-name.html @@ -0,0 +1,139 @@ +--- +title: Census Coverage Survey +project: your-household +globalcss: false +layout: eq-default-extras +cdn: v1.8.4 +hideSaveLater: true +footer: minimal +--- + + +
    +
    + Previous +
    +
    + +
    +
    +
    + {% include navigation.html + title="Your household" + items=site.data.your-household-interview-led.navigationItemsHousehold + %} +
    + +
    +
    + + +
    +
    + +
    +

    + What is your name? +

    + +
    + What is your name? + +
    +
    + + +
    + +
    + + +
    +
    +
    +
    +
    +
    + + +
    +
    +
    +
    + + + + + diff --git a/_prototypes/your-household-interview-led/who-else-to-add.html b/_prototypes/your-household-interview-led/who-else-to-add.html new file mode 100644 index 0000000000..865efe5a8e --- /dev/null +++ b/_prototypes/your-household-interview-led/who-else-to-add.html @@ -0,0 +1,269 @@ +--- +title: Census Coverage Survey +project: your-household +globalcss: false +layout: eq-default-extras +cdn: v1.8.4 +hideSaveLater: true +footer: minimal +--- + + +
    +
    + Previous +
    +
    + +
    +
    +
    + {% include navigation.html + title="Your household" + items=site.data.your-household-interview-led.navigationItemsHousehold + %} +
    +
    +
    + + +
    +
    + +
    +

    + What is the name of the + person living at + +

    + +
    + +
    + What is your name? + +
    +
    + + +
    + +
    + + +
    +
    +
    +
    +
    +
    + + + + +
    +
    +
    +
    + + + + + + +